AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Dotnet Testing

skill-iambrzdev-enterprise-agent-skills-dotnet-testing · by iamBrzDev

>

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-iambrzdev-enterprise-agent-skills-dotnet-testing

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-iambrzdev-enterprise-agent-skills-dotnet-testing)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Dotnet Testing? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

When to activate

  • Writing a unit test or integration test in .NET / C#
  • "What should I mock?" in a .NET testing context
  • Setting up a test project for the first time in a solution
  • Configuring WebApplicationFactory for ASP.NET Core API tests
  • Implementing database isolation for integration tests
  • Testing a MediatR Command, Query, or Handler
  • Testing FluentValidation validators
  • Setting up shared test infrastructure (Docker containers, DB migrations)
  • Any question about xUnit fixtures, test collections, or parallel execution
  • "How do I test this without hitting the real database?"

Rules — Non-negotiable

  1. One Act per test. Strict AAA pattern: one action triggers one outcome.

A test that does two things hides which one failed.

  1. Mock only external/unmanaged dependencies. Moq is for third-party APIs,

email services, payment gateways — not for repositories or domain services. Test those with real implementations.

  1. Integration tests use real databases. In-memory providers (UseInMemoryDatabase)

do not enforce foreign keys, SQL constraints, or stored procedures. Use a real SQL Server instance (Docker) for integration tests.

  1. Every test leaves zero side effects. Use transaction rollback or database

reset between tests. Never rely on test execution order.

  1. Unit tests have zero infrastructure. No database, no file system,

no HTTP calls, no environment variables in unit tests. If you need them, it's an integration test.

Test Project Structure

solution/
├── src/
│   ├── Domain/
│   ├── Application/
│   ├── Infrastructure/
│   └── API/
└── tests/
    ├── Domain.UnitTests/          # Pure domain logic — no mocks needed usually
    ├── Application.UnitTests/     # Handlers, validators — mock output ports
    ├── Infrastructure.IntegrationTests/  # Repositories against real DB
    └── API.IntegrationTests/      # Full HTTP stack via WebApplicationFactory

Each test project mirrors the production project it covers. Test class names: {ClassUnderTest}Tests.cs Test method names: {MethodName}_{Scenario}_{ExpectedResult}

AAA Pattern — Strict Enforcement

[Fact]
public async Task Handle_WhenProductIsOutOfStock_ShouldThrowDomainException()
{
    // Arrange
    var productId = Guid.NewGuid();
    var mockInventory = new Mock();
    mockInventory
        .Setup(x => x.GetStockAsync(productId))
        .ReturnsAsync(0);

    var handler = new CreateOrderCommandHandler(mockInventory.Object);
    var command = new CreateOrderCommand(productId, quantity: 5);

    // Act
    Func act = async () => await handler.Handle(command, CancellationToken.None);

    // Assert
    await act.Should()
        .ThrowAsync()
        .WithMessage("*out of stock*");
}

One Arrange. One Act. One Assert area. Multiple assertions on the same outcome are acceptable. Multiple Act calls are not.

What to Mock vs What Not to Mock

✅ Mock these (unmanaged/external dependencies):
  - Third-party HTTP APIs (payment gateway, SMS provider, external ERP)
  - Email/notification services
  - Current time (IClock, IDateTimeProvider)
  - Random/GUID generation when determinism matters
  - Azure Blob Storage, Azure Service Bus

❌ Never mock these (test with real implementations):
  - Your own repositories (test against real DB in integration tests)
  - Domain services (test with real logic)
  - MediatR pipeline (test handlers directly or via WebApplicationFactory)
  - FluentValidation validators (test the real validator)
  - EF Core DbContext (use real DB, not InMemory)

xUnit Fixtures — Shared Test Infrastructure

Class Fixture — shared within one test class

// Expensive setup shared across all tests in the class (created once)
public class OrderRepositoryTests : IClassFixture
{
    private readonly DatabaseFixture _fixture;

    public OrderRepositoryTests(DatabaseFixture fixture)
    {
        _fixture = fixture;
    }

    [Fact]
    public async Task GetById_WhenOrderExists_ReturnsOrder()
    {
        // Use _fixture.DbContext
    }
}

Collection Fixture — shared across multiple test classes

// shared/DatabaseFixture.cs
public class DatabaseFixture : IAsyncLifetime
{
    public AppDbContext DbContext { get; private set; } = null!;
    private IDbContextTransaction _transaction = null!;

    public async Task InitializeAsync()
    {
        // Start Docker container or connect to test DB
        DbContext = CreateDbContext();
        await DbContext.Database.MigrateAsync();
    }

    // Called before each test — wrap in transaction for isolation
    public async Task BeginTransactionAsync()
    {
        _transaction = await DbContext.Database.BeginTransactionAsync();
    }

    // Called after each test — rollback to leave zero side effects
    public async Task RollbackAsync()
    {
        await _transaction.RollbackAsync();
    }

    public async Task DisposeAsync()
    {
        await DbContext.DisposeAsync();
    }
}

// shared/DatabaseCollection.cs
[CollectionDefinition(nameof(DatabaseCollection))]
public class DatabaseCollection : ICollectionFixture { }

// In test classes that need shared DB:
[Collection(nameof(DatabaseCollection))]
public class ProductRepositoryTests
{
    private readonly DatabaseFixture _fixture;
    public ProductRepositoryTests(DatabaseFixture fixture) => _fixture = fixture;
}

Database Isolation — Transaction Rollback Pattern

The safest isolation strategy: each test runs inside a transaction that rolls back.

public class OrderRepositoryIntegrationTests
    : IClassFixture, IAsyncLifetime
{
    private readonly DatabaseFixture _fixture;

    public OrderRepositoryIntegrationTests(DatabaseFixture fixture)
    {
        _fixture = fixture;
    }

    // Runs before each test
    public async Task InitializeAsync() => await _fixture.BeginTransactionAsync();

    // Runs after each test — database is clean for the next test
    public async Task DisposeAsync() => await _fixture.RollbackAsync();

    [Fact]
    public async Task Save_ValidOrder_PersistsToDatabase()
    {
        // Arrange
        var repository = new OrderRepository(_fixture.DbContext);
        var order = Order.Create(Guid.NewGuid(), "customer-1");

        // Act
        await repository.SaveAsync(order);
        await _fixture.DbContext.SaveChangesAsync();

        // Assert
        var saved = await repository.GetByIdAsync(order.Id);
        saved.Should().NotBeNull();
        saved!.CustomerId.Should().Be("customer-1");
        // Transaction rolls back after this test — no cleanup needed
    }
}

Integration Tests — WebApplicationFactory

// shared/ApiFactory.cs
public class ApiFactory : WebApplicationFactory, IAsyncLifetime
{
    // Override to swap real DB with test DB
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // Remove real DbContext registration
            var descriptor = services.SingleOrDefault(
                d => d.ServiceType == typeof(DbContextOptions));
            if (descriptor != null) services.Remove(descriptor);

            // Register test DB
            services.AddDbContext(options =>
                options.UseSqlServer(TestConnectionString));
        });
    }

    public async Task InitializeAsync() => await ResetDatabaseAsync();
    public new async Task DisposeAsync() => await base.DisposeAsync();
}

// API test example
[Collection(nameof(ApiCollection))]
public class OrdersEndpointTests
{
    private readonly HttpClient _client;

    public OrdersEndpointTests(ApiFactory factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task POST_Orders_WithValidRequest_Returns201()
    {
        // Arrange
        var request = new { ProductId = Guid.NewGuid(), Quantity = 2 };

        // Act
        var response = await _client.PostAsJsonAsync("/api/v1/orders", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var body = await response.Content.ReadFromJsonAsync();
        body!.Id.Should().NotBeEmpty();
    }
}

Testing MediatR Handlers

Test handlers directly — do not mock MediatR itself:

[Fact]
public async Task CreateOrderHandler_WithValidCommand_ReturnsOrderId()
{
    // Arrange — use real domain objects, mock only external ports
    var mockInventory = new Mock();
    mockInventory.Setup(x => x.IsAvailableAsync(It.IsAny(), It.IsAny()))
        .ReturnsAsync(true);

    var handler = new CreateOrderCommandHandler(
        _fixture.OrderRepository,   // real repository — integration test
        mockInventory.Object        // mocked — external dependency
    );

    var command = new CreateOrderCommand(Guid.NewGuid(), quantity: 1);

    // Act
    var result = await handler.Handle(command, CancellationToken.None);

    // Assert
    result.OrderId.Should().NotBeEmpty();
}

Testing FluentValidation

[Fact]
public void Validate_WhenQuantityIsZero_ShouldHaveValidationError()
{
    // Arrange
    var validator = new CreateOrderCommandValidator();
    var command = new CreateOrderCommand(Guid.NewGuid(), quantity: 0);

    // Act
    var result = validator.Validate(command);

    // Assert
    result.IsValid.Should().BeFalse();
    result.Errors.Should().ContainSingle(e =>
        e.PropertyName == nameof(CreateOrderCommand.Quantity) &&
        e.ErrorMessage.Contains("greater than"));
}

Common mistakes

  • UseInMemoryDatabase() for integration tests — misses SQL constraints and FK violations
  • ✅ Use a real SQL Server in Docker (Testcontainers or a dedicated test instance)
  • [Theory] with 20 inline data cases that all test the same code path
  • ✅ Group data-driven tests by behavior, not by data variation
  • ❌ Static shared state between tests (static List _orders)
  • ✅ Each test creates its own data; transaction rollback handles cleanup
  • ❌ Mocking IOrderRepository in integration tests to avoid the database
  • ✅ That makes it a unit test — name it and place it accordingly
  • Assert.True(result != null) — no context when it fails
  • result.Should().NotBeNull("because a valid command must return an order")

Definition of Done

A test suite built with this skill is complete only when:

  • [ ] Unit tests have zero infrastructure dependencies (no DB, no HTTP, no FS)
  • [ ] Integration tests run against a real SQL Server (not InMemory)
  • [ ] Each integration test leaves zero side effects (transaction rollback or reset)
  • [ ] Moq is used only for external/unmanaged dependencies
  • [ ] Test method names follow {Method}_{Scenario}_{ExpectedResult} convention
  • [ ] FluentAssertions used throughout — no raw Assert.Equal
  • [ ] All tests pass in parallel with no ordering dependency

Reference files

Load on demand:

  • references/testcontainers-setup.md — SQL Server in Docker for integration tests
  • references/handler-testing-patterns.md — full patterns for CQRS handler test suites
  • references/coverage-thresholds.md — configuring coverage gates in Azure Pipelines

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.