Skip to main content

testing-guide

Write tests for an FSH feature — xUnit + Shouldly + NSubstitute + AutoFixture, with naming and AAA conventions. Use when adding unit/handler/validator/entity tests. Full rules in .agents/rules/testing.md + integration-testing.md.

Informations de source

Dépôt
fullstackhero/dotnet-starter-kit
Dernière activité de la source
25 septembre 2026 à 01:46
Langue détectée de SKILL.md
anglais
Étoiles
6 813
Forks
2 003

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
testing-guide
description
Write tests for an FSH feature — xUnit + Shouldly + NSubstitute + AutoFixture, with naming and AAA conventions. Use when adding unit/handler/validator/entity tests. Full rules in .agents/rules/testing.md + integration-testing.md.
# Testing Guide Stack: **xUnit** + **Shouldly** (`.ShouldBe`) + **NSubstitute** (`Substitute.For<>`) + **AutoFixture** (`new Fixture()`). **Not** Moq, **not** FluentAssertions. Detailed conventions + integration-test gotchas live in `.agents/rules/testing.md` and `.agents/rules/integration-testing.md`. ## Conventions - Test class: `public sealed class {Sut}Tests`; SUT field named `_sut`. - Method name: **`MethodName_Should_ExpectedBehavior[_When_Condition]`**. - Arrange-Act-Assert with `// Arrange` / `// Act` / `// Assert`; group with `#region` (Happy Path / Guards / Edge Cases). - Mocks via `Substitute.For<IService>()`; assert calls with `.Received(1).X(arg, Arg.Any<CancellationToken>())`. - When asserting a forwarded `CancellationToken`, assert the **specific** token, not the default (NSubstitute fills optional params with `default`). ## Handler test ```csharp public sealed class Create{Entity}CommandHandlerTests { private readonly {X}DbContext _db; // or Substitute.For<IService>() for service deps private readonly Create{Entity}CommandHandler _sut; private readonly IFixture _fixture = new Fixture(); public Create{Entity}CommandHandlerTests() { _db = /* in-memory or test DbContext */; _sut = new Create{Entity}CommandHandler(_db); } [Fact] public async Task Handle_Should_PersistEntity_And_ReturnId() { // Arrange var command = new Create{Entity}Command(_fixture.Create<string>(), 9.99m, "USD"); // Act var id = await _sut.Handle(command, CancellationToken.None); // Assert id.ShouldNotBe(Guid.Empty); } } ``` Service-dependency example (NSubstitute): ```csharp _userService = Substitute.For<IUserService>(); // Act … then: await _userService.Received(1).ToggleStatusAsync(true, command.UserId, Arg.Any<CancellationToken>()); ``` ## Validator test ```csharp public sealed class Create{Entity}CommandValidatorTests { private readonly Create{Entity}CommandValidator _sut = new(); [Theory] [InlineData("")] public void Validate_Should_Fail_When_NameInvalid(string name) { var result = _sut.Validate(new Create{Entity}Command(name, 1m, "USD")); result.IsValid.ShouldBeFalse(); result.Errors.ShouldContain(e => e.PropertyName == nameof(Create{Entity}Command.Name)); } } ``` ## Entity / domain test (no mocks) ```csharp [Fact] public void Create_Should_RaiseCreatedEvent() { var entity = {Entity}.Create("Test", Money.Zero()); entity.Id.ShouldNotBe(Guid.Empty); entity.DomainEvents.ShouldContain(e => e is {Entity}CreatedDomainEvent); } ``` ## Architecture tests (guardrails — keep green) `Architecture.Tests` (NetArchTest) enforce: module boundaries (cross-module refs only via `.Contracts`), tenant-isolation rules, handlers `sealed`, and **every command/paginated-query handler has a validator**. Don't weaken these to make a change pass — fix the code. ## Integration tests `Integration.Tests` runs over real Postgres/Redis/RustFS via Testcontainers — **Docker required**. Set the Finbuckle tenant context inline, rewire `IStorageService` post-registration for RustFS (S3), force long-polling for SignalR. All detailed in `.agents/rules/integration-testing.md`. ## Run ```bash dotnet test src/Tests/{X}.Tests dotnet test src/Tests/Architecture.Tests dotnet test src/FSH.Starter.slnx --collect "XPlat Code Coverage" --settings coverage.runsettings ```
Voir sur GitHub