Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
affaan-m avatar

Csharp Testing

  • 4.2k installs
  • 238k repo stars
  • Updated August 5, 2026
  • affaan-m/everything-claude-code

Proven patterns for writing unit, integration, and API tests in C# and .NET using xUnit, FluentAssertions, NSubstitute, Testcontainers, and WebApplicationFactory.

About

Comprehensive testing patterns for .NET applications using xUnit as the primary framework, FluentAssertions for readable assertions, NSubstitute or Moq for mocking dependencies, and Testcontainers for integration tests with real infrastructure. Covers unit test structure via Arrange-Act-Assert, parameterized tests with Theory and InlineData, mocking workflows for repository and service layers, ASP.NET Core integration testing with WebApplicationFactory and in-memory databases, and database testing with Testcontainers. Includes test organization strategies, developers pattern for test data generation, and common antipatterns to avoid such as testing implementation details, shared mutable state, and poor test naming conventions. xUnit framework with Fact and Theory attributes for parameterized test cases. FluentAssertions for fluent, readable assertion syntax in test assertions. NSubstitute mocking for dependencies with verification of method calls and arguments. WebApplicationFactory integration testing for ASP.NET Core APIs with in-memory databases.

  • xUnit framework with Fact and Theory attributes for parameterized test cases
  • FluentAssertions for fluent, readable assertion syntax in test assertions
  • NSubstitute mocking for dependencies with verification of method calls and arguments
  • WebApplicationFactory integration testing for ASP.NET Core APIs with in-memory databases
  • Testcontainers for real infrastructure setup in integration tests (PostgreSQL example included)

Csharp Testing by the numbers

  • 4,196 all-time installs (skills.sh)
  • +224 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #289 of 2,153 Testing & QA skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

csharp-testing capabilities & compatibility

Capabilities
write unit tests with xunit fact and theory · create fluent assertions with fluentassertions · mock dependencies with nsubstitute · test asp.net core apis with webapplicationfactor · integration testing with real databases via test · test data generation with builders · organize test projects and avoid antipatterns
Works with
github · gitlab · bitbucket
Use cases
testing · debugging · code review
Platforms
macOS · Windows · Linux · WSL
Runs
Runs locally
npx skills add https://github.com/affaan-m/everything-claude-code --skill csharp-testing

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs4.2k
repo stars238k
Security audit3 / 3 scanners passed
Last updatedAugust 5, 2026
Repositoryaffaan-m/everything-claude-code

What it does

Write and organize unit, integration, and API tests for C# and .NET applications using xUnit, FluentAssertions, and mocking.

Who is it for?

C# and .NET developers writing tests for services, repositories, validators, and ASP.NET Core APIs.

Skip if: Frontend-only projects, Python/Go/Rust codebases, projects not using .NET framework.

When should I use this skill?

Writing new tests, reviewing test quality, setting up test infrastructure, debugging flaky tests.

What you get

Developers write comprehensive test suites with clear organization, reduced flakiness, and confidence in code coverage.

  • Unit test files (xUnit Fact and Theory tests)
  • Integration test files with WebApplicationFactory
  • Testcontainers-based database tests

By the numbers

  • xUnit, FluentAssertions, NSubstitute, Testcontainers, WebApplicationFactory, Bogus are 6 core tools covered
  • Includes Arrange-Act-Assert, Theory/InlineData, parameterized testing, mocking, and integration patterns
  • 3 levels of testing covered: unit (OrderServiceTests), integration (OrderApiTests), and database (PostgresOrderRepositor

Files

SKILL.mdMarkdownGitHub ↗

C#テストパターン

xUnit、FluentAssertions、最新のテストプラクティスを使用した.NETアプリケーションの包括的なテストパターン。

起動条件

  • C#コードの新しいテストを書く場合
  • テスト品質とカバレッジのレビュー
  • .NETプロジェクトのテストインフラストラクチャの設定
  • フレーキーまたは遅いテストのデバッグ

テストフレームワークスタック

ツール目的
xUnitテストフレームワーク(.NETに推奨)
FluentAssertions読みやすいアサーション構文
NSubstituteまたはMoq依存関係のモッキング
Testcontainers統合テストでの実際のインフラ
WebApplicationFactoryASP.NET Core統合テスト
Bogus現実的なテストデータ生成

ユニットテスト構造

Arrange-Act-Assert

public sealed class OrderServiceTests
{
    private readonly IOrderRepository _repository = Substitute.For<IOrderRepository>();
    private readonly ILogger<OrderService> _logger = Substitute.For<ILogger<OrderService>>();
    private readonly OrderService _sut;

    public OrderServiceTests()
    {
        _sut = new OrderService(_repository, _logger);
    }

    [Fact]
    public async Task PlaceOrderAsync_ReturnsSuccess_WhenRequestIsValid()
    {
        // Arrange
        var request = new CreateOrderRequest
        {
            CustomerId = "cust-123",
            Items = [new OrderItem("SKU-001", 2, 29.99m)]
        };

        // Act
        var result = await _sut.PlaceOrderAsync(request, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        result.Value.Should().NotBeNull();
        result.Value!.CustomerId.Should().Be("cust-123");
    }

    [Fact]
    public async Task PlaceOrderAsync_ReturnsFailure_WhenNoItems()
    {
        // Arrange
        var request = new CreateOrderRequest
        {
            CustomerId = "cust-123",
            Items = []
        };

        // Act
        var result = await _sut.PlaceOrderAsync(request, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeFalse();
        result.Error.Should().Contain("at least one item");
    }
}

Theoryによるパラメータ化テスト

[Theory]
[InlineData("", false)]
[InlineData("a", false)]
[InlineData("ab@c.d", false)]
[InlineData("user@example.com", true)]
[InlineData("user+tag@example.co.uk", true)]
public void IsValidEmail_ReturnsExpected(string email, bool expected)
{
    EmailValidator.IsValid(email).Should().Be(expected);
}

[Theory]
[MemberData(nameof(InvalidOrderCases))]
public async Task PlaceOrderAsync_RejectsInvalidOrders(CreateOrderRequest request, string expectedError)
{
    var result = await _sut.PlaceOrderAsync(request, CancellationToken.None);

    result.IsSuccess.Should().BeFalse();
    result.Error.Should().Contain(expectedError);
}

public static TheoryData<CreateOrderRequest, string> InvalidOrderCases => new()
{
    { new() { CustomerId = "", Items = [ValidItem()] }, "CustomerId" },
    { new() { CustomerId = "c1", Items = [] }, "at least one item" },
    { new() { CustomerId = "c1", Items = [new("", 1, 10m)] }, "SKU" },
};

NSubstituteによるモッキング

[Fact]
public async Task GetOrderAsync_ReturnsNull_WhenNotFound()
{
    // Arrange
    var orderId = Guid.NewGuid();
    _repository.FindByIdAsync(orderId, Arg.Any<CancellationToken>())
        .Returns((Order?)null);

    // Act
    var result = await _sut.GetOrderAsync(orderId, CancellationToken.None);

    // Assert
    result.Should().BeNull();
}

[Fact]
public async Task PlaceOrderAsync_PersistsOrder()
{
    // Arrange
    var request = ValidOrderRequest();

    // Act
    await _sut.PlaceOrderAsync(request, CancellationToken.None);

    // Assert — リポジトリが呼び出されたことを検証
    await _repository.Received(1).AddAsync(
        Arg.Is<Order>(o => o.CustomerId == request.CustomerId),
        Arg.Any<CancellationToken>());
}

ASP.NET Core統合テスト

WebApplicationFactoryのセットアップ

public sealed class OrderApiTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;

    public OrderApiTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                // テスト用にインメモリDBで実際のDBを置き換え
                services.RemoveAll<DbContextOptions<AppDbContext>>();
                services.AddDbContext<AppDbContext>(options =>
                    options.UseInMemoryDatabase("TestDb"));
            });
        }).CreateClient();
    }

    [Fact]
    public async Task GetOrder_Returns404_WhenNotFound()
    {
        var response = await _client.GetAsync($"/api/orders/{Guid.NewGuid()}");

        response.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task CreateOrder_Returns201_WithValidRequest()
    {
        var request = new CreateOrderRequest
        {
            CustomerId = "cust-1",
            Items = [new("SKU-001", 1, 19.99m)]
        };

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

        response.StatusCode.Should().Be(HttpStatusCode.Created);
        response.Headers.Location.Should().NotBeNull();
    }
}

Testcontainersによるテスト

public sealed class PostgresOrderRepositoryTests : IAsyncLifetime
{
    private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder()
        .WithImage("postgres:16-alpine")
        .Build();

    private AppDbContext _db = null!;

    public async Task InitializeAsync()
    {
        await _postgres.StartAsync();
        var options = new DbContextOptionsBuilder<AppDbContext>()
            .UseNpgsql(_postgres.GetConnectionString())
            .Options;
        _db = new AppDbContext(options);
        await _db.Database.MigrateAsync();
    }

    public async Task DisposeAsync()
    {
        await _db.DisposeAsync();
        await _postgres.DisposeAsync();
    }

    [Fact]
    public async Task AddAsync_PersistsOrder()
    {
        var repo = new SqlOrderRepository(_db);
        var order = Order.Create("cust-1", [new OrderItem("SKU-001", 2, 10m)]);

        await repo.AddAsync(order, CancellationToken.None);

        var found = await repo.FindByIdAsync(order.Id, CancellationToken.None);
        found.Should().NotBeNull();
        found!.Items.Should().HaveCount(1);
    }
}

テスト組織

tests/
  MyApp.UnitTests/
    Services/
      OrderServiceTests.cs
      PaymentServiceTests.cs
    Validators/
      EmailValidatorTests.cs
  MyApp.IntegrationTests/
    Api/
      OrderApiTests.cs
    Repositories/
      OrderRepositoryTests.cs
  MyApp.TestHelpers/
    Builders/
      OrderBuilder.cs
    Fixtures/
      DatabaseFixture.cs

テストデータビルダー

public sealed class OrderBuilder
{
    private string _customerId = "cust-default";
    private readonly List<OrderItem> _items = [new("SKU-001", 1, 10m)];

    public OrderBuilder WithCustomer(string customerId)
    {
        _customerId = customerId;
        return this;
    }

    public OrderBuilder WithItem(string sku, int quantity, decimal price)
    {
        _items.Add(new OrderItem(sku, quantity, price));
        return this;
    }

    public Order Build() => Order.Create(_customerId, _items);
}

// テストでの使用
var order = new OrderBuilder()
    .WithCustomer("cust-vip")
    .WithItem("SKU-PREMIUM", 3, 99.99m)
    .Build();

よくあるアンチパターン

アンチパターン修正方法
実装の詳細をテストする動作と結果をテストする
共有の可変テスト状態テストごとに新しいインスタンス(xUnitはコンストラクタでこれを行う)
非同期テストでのThread.Sleepタイムアウトまたはポーリングヘルパーを使用したTask.Delay
ToString()出力のアサーション型付きプロパティのアサーション
テストごとに1つの巨大なアサーションテストごとに1つの論理的なアサーション
実装を記述するテスト名動作で命名: Method_ExpectedResult_WhenCondition
CancellationTokenを無視する常に渡してキャンセルを確認する

テストの実行

# すべてのテストを実行
dotnet test

# カバレッジを付けて実行
dotnet test --collect:"XPlat Code Coverage"

# 特定のプロジェクトを実行
dotnet test tests/MyApp.UnitTests/

# テスト名でフィルタリング
dotnet test --filter "FullyQualifiedName~OrderService"

# 開発中のウォッチモード
dotnet watch test --project tests/MyApp.UnitTests/

Related skills

Forks & variants (1)

Csharp Testing has 1 known copy in the catalog totaling 1.4k installs. They canonicalize to this original listing.

FAQ

What is the difference between xUnit Fact and Theory?

Fact runs a single test; Theory runs multiple tests with different InlineData or MemberData parameters.

Should I use NSubstitute or Moq?

Both are valid; NSubstitute is simpler, Moq is more widely used. Choose based on team preference.

How do I avoid flaky async tests?

Use Task.Delay instead of Thread.Sleep, always pass CancellationToken, and use Testcontainers for real infrastructure.

Is Csharp Testing safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.