← Back to Blog

ASP.NET Zero

How to Test AI-Generated Code Before You Merge It: 6 ASP.NET Zero Unit Tests

How to Test AI-Generated Code Before You Merge It: 6 ASP.NET Zero Unit Tests

Your AI assistant just generated a new InvoiceAppService. The project builds and the admin page works. But have you tested what happens when someone tries to do something they aren’t allowed to do?

It created the interface, DTOs, mapping profile, and even the Angular service call. The project builds. You log in as an admin, click through the page, and everything appears to work.

But there’s one problem.

You haven’t tested what happens when someone tries to do something they aren’t allowed to do.

Can a user without invoice permissions create an invoice? Can one tenant access another tenant’s records? Can a regular tenant user call a method intended only for the Host?

These are the kinds of problems that a successful build or a quick UI walkthrough won’t necessarily catch.

AI-generated code can save development time, but it still needs proper testing before it reaches production. A July 2026 study of 4,882 AI-generated pull requests found that coding agents added test changes in only 49.6% of pull requests that modified code under test. That leaves plenty of room for missing test coverage.

For an ASP.NET Zero application, the risks can be especially important because application services often enforce permissions, tenant boundaries, and business rules.

In this guide, we’ll cover six ASP.NET Zero unit tests worth running before merging an AI-generated AppService.

The examples are based on the standard ASP.NET Zero test-project approach. Helper methods and class names may need to be adapted to your solution and framework version.

Contents

Key Takeaways

  • Use the existing ASP.NET Zero test project instead of building a separate testing setup.
  • Test what happens when a user does not have permission, not only when an administrator succeeds.
  • Verify that tenant users cannot access another tenant’s data.
  • Test Host-only operations with both tenant and Host users.
  • Validate DTO inputs and tenant feature restrictions.
  • Let AI help generate test code, but have a developer decide what each test must prove.

Is AI-Generated Code Safe to Merge?

AI-generated code isn’t automatically unsafe. The problem is assuming that code is correct simply because it compiles or works in one scenario.

An AI coding assistant works with the instructions, code, and context you provide. It may not know every business rule in your application.

For example, it might generate an invoice service that:

  • Doesn’t include the required [AbpAuthorize] attribute.
  • Uses a query that doesn’t respect tenant boundaries.
  • Allows a tenant user to call a Host-only operation.
  • Misses a [Required] or [StringLength] validation rule.
  • Ignores whether a particular feature is enabled for the tenant.

The application may still build successfully.

This is why testing AI-generated code needs to go beyond the happy path.

Before merging an AI-written AppService, you should be able to prove that the correct permissions are enforced, tenant data stays isolated, Host-only operations remain restricted, and invalid inputs are rejected.

A code review is important, but a test that fails when a security rule is removed gives you something more concrete to verify.

What Does the ASP.NET Zero Test Project Already Provide?

Before creating a new testing setup, check the test project included in your ASP.NET Zero solution.

The standard template provides an application testing foundation built around tools such as:

  • xUnit for writing and running tests.
  • Abp.TestBase for initializing the ABP test environment.
  • Shouldly for readable assertions.
  • An in-memory database setup for application tests.

Test classes commonly derive from AppTestBase, which provides the test initialization and supporting infrastructure.

The template also includes login helpers such as LoginAsDefaultTenantAdmin().

This is useful for testing normal application operations, but it can also create a blind spot.

A tenant administrator usually has broad permissions within that tenant. If every test runs as an administrator, a missing authorization attribute may go unnoticed.

Your tests need to include users who should fail, not only users who should succeed.

Six ASP.NET Zero Unit Tests to Run Before You Merge

Let’s use an InvoiceAppService as an example.

The goal isn’t to test every line of generated code. It’s to test the rules that could cause real problems if the AI assistant overlooked them.

1. Test the Happy Path: Can a Valid User Create an Invoice?

Start with a basic test to confirm that the service works for an authorized user.

public class InvoiceAppService_Tests : AppTestBase
{
    private readonly IInvoiceAppService _invoiceAppService;

    public InvoiceAppService_Tests()
    {
        LoginAsDefaultTenantAdmin();
        _invoiceAppService = Resolve<IInvoiceAppService>();
    }

    [Fact]
    public async Task Should_Create_Invoice()
    {
        await _invoiceAppService.Create(
            new CreateInvoiceInput
            {
                Number = "INV-1001",
                Total = 120m
            });

        UsingDbContext(context =>
        {
            context.Invoices
                .FirstOrDefault(i => i.Number == "INV-1001")
                .ShouldNotBeNull();
        });
    }
}

This verifies that an authorized user can execute the operation and that the invoice is persisted.

It is a useful starting point, but it doesn’t prove that the permission rules are working.

For that, you need the next test.

2. Test Permission Restrictions: What Happens Without Access?

Now try the same operation with a user who doesn’t have the invoice creation permission.

Create a test user without the required role or permission, log in as that user, and attempt the operation.

[Fact]
public async Task Should_Not_Create_Invoice_Without_Permission()
{
    var user = await CreateUserWithoutRolesAsync(
        "no.permission"
    );

    LoginAsTenant("Default", user.UserName);

    await Should.ThrowAsync<AbpAuthorizationException>(
        async () => await _invoiceAppService.Create(
            new CreateInvoiceInput
            {
                Number = "INV-1002",
                Total = 10m
            })
    );
}

CreateUserWithoutRolesAsync and LoginAsTenant are illustrative helpers. Implement them using the user creation and login utilities available in your test project. The expected exception should also match the authorization behavior of your ABP version.

Here’s an important review technique:

Temporarily remove the [AbpAuthorize] attribute and run the test again.

If the test still passes, it isn’t proving the authorization rule you intended to test.

3. Test Tenant Isolation: Can Tenant A Access Tenant B’s Data?

Multi-tenancy is one of the most important areas to test in an ASP.NET Zero application.

Imagine two customers using the same SaaS platform:

  • Tenant A manages its own invoices.
  • Tenant B manages its own invoices.

Tenant A should never receive Tenant B’s records through a normal tenant-scoped query.

Create an invoice under another tenant, then query the service as a user from the Default tenant.

[Fact]
public async Task Should_Not_Return_Other_Tenant_Invoices()
{
    var otherTenantId =
        await CreateTestTenantAsync("other");

    UsingDbContext(otherTenantId, context =>
    {
        context.Invoices.Add(new Invoice
        {
            TenantId = otherTenantId,
            Number = "OTHER-1",
            Total = 5m
        });
    });

    LoginAsDefaultTenantAdmin();

    var result = await _invoiceAppService.GetAll(
        new GetInvoicesInput()
    );

    result.Items.ShouldNotContain(
        i => i.Number == "OTHER-1"
    );
}

The tenant creation and context helpers are illustrative. Make sure the test actually saves the record under the other tenant and that the service query runs under the intended tenant context.

This test can help catch problems such as:

  • Queries that bypass tenant filters.
  • Incorrect use of IgnoreQueryFilters().
  • Repository operations that disable tenant filtering unexpectedly.
  • Missing tenant restrictions in custom data access logic.

A query returning the correct records for one tenant doesn’t prove that it protects every other tenant.

4. Test Host-Only Operations: Can a Tenant User Call Them?

Some operations should only be available from the Host side.

For example, imagine an operation that recalculates information across all tenants.

A tenant administrator shouldn’t be able to execute it.

Test both sides of the restriction:

[Fact]
public async Task Tenant_Admin_Cannot_Call_Host_Method()
{
    LoginAsDefaultTenantAdmin();

    await Should.ThrowAsync<AbpAuthorizationException>(
        async () =>
            await _invoiceAppService.RecalculateAllTenants()
    );
}

Then add a separate positive test to verify that an appropriately authorized Host user can execute the operation.

The exact Host login helper and expected exception depend on your template and authorization configuration.

Don’t assume that a method is Host-only just because its name suggests it. Test the actual authorization and tenant-side restrictions configured in your application.

5. Test Input Validation: What Happens When Required Data Is Missing?

AI-generated DTOs can look complete while missing important validation attributes.

For example, your database might restrict an invoice number to 50 characters, but the generated DTO may accept a much longer value.

Review your input DTO and test its validation rules.

[Fact]
public async Task Should_Reject_Invalid_Invoice_Input()
{
    var input = new CreateInvoiceInput
    {
        Number = new string('A', 100),
        Total = 120m
    };

    await Should.ThrowAsync<AbpValidationException>(
        async () =>
            await _invoiceAppService.Create(input)
    );
}

This example assumes the DTO has an applicable length constraint and that the AppService validation pipeline enforces it.

Repeat the test for important fields such as:

  • Required invoice numbers.
  • Invalid amounts.
  • Missing customer references.
  • Values exceeding configured length limits.
  • Invalid dates or other business-specific constraints.

The important thing is to test the rules your application actually requires, not just whether the DTO accepts a request.

6. Test Feature Dependencies: What If the Tenant Doesn’t Have the Feature?

Permissions and feature availability are different checks.

A user may have a permission associated with an AI reporting operation, but their tenant may not have the AI reporting feature enabled.

Your application should reject the operation when its required feature is unavailable.

For example, if an AppService method depends on MyAiFeature, write a test that disables that feature for the test tenant and attempts the operation.

[Fact]
public async Task Should_Not_Run_When_Ai_Feature_Is_Disabled()
{
    LoginAsDefaultTenantAdmin();

    // Disable MyAiFeature for the test tenant
    // using the feature-management setup
    // available in your ASP.NET Zero version.

    await Should.ThrowAsync<Exception>(
        async () =>
            await _invoiceAppService.GenerateAiReport()
    );
}

This is a test outline, not a drop-in implementation. Replace the feature setup with the feature-management API available in your version, and assert the specific exception your application throws when the feature is unavailable.

The test should prove that a user cannot execute a feature-dependent operation simply because they have a permission or can see the corresponding button.

Should You Ask AI to Write the Tests Before the AppService?

Yes. This is a useful way to make requirements clearer before implementation begins.

Instead of asking an AI assistant to generate the entire AppService immediately, provide it with:

  • The AppService interface.
  • The input and output DTOs.
  • The relevant permission names.
  • The tenant and Host restrictions.
  • The feature dependencies.
  • The expected validation rules.

Then ask it to draft the tests first.

Review the tests before accepting the implementation.

Ask yourself:

  • Does the permission test fail when authorization is removed?
  • Does the tenant test fail if tenant filtering is bypassed?
  • Does the Host-only test reject tenant users?
  • Does the validation test catch invalid input?
  • Does the feature test fail when the feature is disabled?

AI can help generate the test skeletons and arrange the test data. But a developer should decide which application rule each test must prove.

What Should You Automate and What Should Stay With Developers?

You don’t need to manually repeat every testing step after each AI-generated change.

A good workflow separates repetitive execution from engineering decisions.

Automate Keep with a developer
Generate test skeletons from AppService interfaces Decide which permissions each method requires
Run unit tests in CI for every pull request Define tenant and Host access rules
Re-run tests after AI changes Review whether tests prove the intended behavior
Flag AppServices without test coverage Decide whether a failing test reveals a code defect or an incorrect requirement
Report failed assertions Approve the final implementation

The purpose of automation is to make verification consistent, not to remove engineering judgment.

Additional Cases Worth Testing

The six tests above cover important AppService risks, but some applications need additional coverage.

Background jobs: If an AppService schedules a background job, test that it executes with the correct tenant and user context. A background worker shouldn’t accidentally perform tenant work as Host.

Feature dependencies: Test the feature-enabled and feature-disabled scenarios, especially for tenant-specific capabilities.

Angular permissions: A button hidden through permission.isGranted improves the interface, but it doesn’t replace server-side authorization. Test the AppService itself.

HTTP integration: Application-layer unit tests don’t replace integration tests for routing, authentication, serialization, and the actual HTTP pipeline.

Frequently Asked Questions

How do I test AI-generated code before merging it?

Start with the application’s existing test suite. Test normal operations, permission failures, data isolation, validation, and important business rules. Run the tests in CI before merging the generated code.

Is AI-generated code safe to use in production?

It can be, provided it goes through the same review, testing, and security checks as code written by a developer. A successful build alone doesn’t prove that generated code follows your application’s business rules.

Does ASP.NET Zero support unit testing for AppServices?

The standard ASP.NET Zero solution includes a test-project approach using ABP testing infrastructure. AppTestBase is commonly used to initialize the test environment and resolve application services. Check the template version used by your project because the exact setup can differ.

Should I test permissions separately from normal functionality?

Yes. A happy-path test proves that an authorized user can perform an operation. It doesn’t prove that an unauthorized user will be rejected. Both scenarios matter.

Do unit tests cover multi-tenancy security?

They can verify important tenant-isolation rules at the application layer. However, they should be complemented by integration tests where necessary to verify the full request and authentication pipeline.

Conclusion: Don’t Merge AI-Generated Code Just Because It Works

AI assistants can generate an AppService in minutes. But the speed of implementation doesn’t guarantee that permissions, tenant isolation, and validation rules are correct.

Before merging AI-generated code into an ASP.NET Zero application, test more than the happy path.

Verify that unauthorized users are rejected, tenant data stays isolated, Host-only operations remain protected, and invalid inputs never reach your business logic.

Most importantly, don’t let an administrator account become the only user in your test suite.

The real question isn’t whether AI can write your AppService. It’s whether your tests can catch what the AI missed.

Need help adding proper unit tests to an ASP.NET Zero codebase that has grown quickly with AI assistance? Our dedicated ASP.NET Zero teams include QA testers, and testing is part of delivering the feature.

Get In Touch

Ready to start your ASP.NET Zero project?

Hire ASP.Net Zero Application Developers that will provide the perfect solution to your business issues. Our technical experts will provide you with a free consultation.

More from the Blog