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.

Quellinformationen

Repository
fullstackhero/dotnet-starter-kit
Letzte Quellaktivität
25. September 2026 um 01:46
Erkannte Sprache von SKILL.md
Englisch
Sterne
6.818
Forks
2.003

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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 ```
Auf GitHub ansehen