Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
中文简介正在准备中。当前显示原文说明。
Use when writing tests for C#/.NET code - xUnit structure, NSubstitute or the repository's mocking library at ports, WebApplicationFactory for HTTP, Testcontainers Postgres for EF Core, FakeTimeProvider, test-first
中文简介正在准备中。当前显示原文说明。
安装前可以查看交给 AI 代理的指令内容。
Test-first in C#, same discipline as everywhere (see tdd-workflow): write the failing test, watch it fail, minimal code to pass. This skill is the .NET mechanics for that cycle.
Core principle: unit-test the domain and services as plain C# without starting the host. Start the host (WebApplicationFactory) only where wiring, serialization, validation or SQL is what you are proving.
| Level | What it covers | Tools |
|---|---|---|
| Unit | Domain entity / value object, no mocks | xUnit [Fact] / [Theory] |
| Unit with fakes | Application service, its ports faked | xUnit + NSubstitute (or the repository's Moq / FakeItEasy) |
| Persistence | Repository / DbContext queries against real Postgres | Testcontainers PostgreSqlContainer + the repository's migrations |
| HTTP | Endpoint wiring, binding, validation, ProblemDetails, auth | WebApplicationFactory<Program> (Microsoft.AspNetCore.Mvc.Testing) + HttpClient |
Most tests are the first two. Match the repository's framework: xUnit (v3 for new projects; v2 where the repository is on it), NUnit or MSTest — never add a second one.
public sealed class TaskServiceTests
{
private readonly ITaskRepository _repo = Substitute.For<ITaskRepository>();
private readonly FakeTimeProvider _clock = new(DateTimeOffset.Parse("2026-01-01T00:00:00Z"));
private readonly TaskService _service;
public TaskServiceTests() => _service = new TaskService(_repo, _clock);
[Fact]
public async Task Create_persists_and_returns_the_task()
{
var task = await _service.CreateAsync("Write the report", CancellationToken.None);
Assert.Equal("Write the report", task.Title);
await _repo.Received(1).AddAsync(task, Arg.Any<CancellationToken>());
}
[Theory]
[InlineData("")]
[InlineData(" ")]
public async Task Create_rejects_a_blank_title(string title)
{
await Assert.ThrowsAsync<InvalidTaskTitleException>(() => _service.CreateAsync(title, CancellationToken.None));
await _repo.DidNotReceiveWithAnyArgs().AddAsync(default!, default);
}
}
Received(...) alone proves only that the fake was called.Create_rejects_a_blank_title). [Theory] + [InlineData] / [MemberData] for boundary tables (200 characters accepted, 201 rejected).TimeProvider in production code, FakeTimeProvider (Microsoft.Extensions.TimeProvider.Testing) in tests — never DateTime.Now in either.IAsyncLifetime / a collection fixture), migrations applied once, data reset between tests (Respawn, or a transaction rolled back per test).WebApplicationFactory<Program> with ConfigureTestServices replacing only the external dependencies (payment gateway, clock), not the services under test. Assert the status code AND the body shape (ProblemDetails type/errors). On .NET 9 or earlier a top-level-statement Program needs public partial class Program; for the factory to see it.Assert, Shouldly or AwesomeAssertions are the free options. Do not add Moq to a project that uses NSubstitute or the other way round.async tests return Task, never async void; pass TestContext.Current.CancellationToken (xUnit v3) where the API takes one.dotnet test --filter "FullyQualifiedName~TaskServiceTests"; the whole dotnet test before you stop. Coverage through the repository's collector (coverlet --collect:"XPlat Code Coverage" or Microsoft.Testing.Platform --coverage); mutation testing, where the repository runs it, is Stryker.NET.WebApplicationFactory test for every service rule — slow, and it hides design problems a plain unit test would show.Thread.Sleep / Task.Delay to wait for time to pass instead of advancing FakeTimeProvider.[Fact(Skip = ...)] added to make the suite green.还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
中文简介正在准备中。当前显示原文说明。
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
中文简介正在准备中。当前显示原文说明。
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
中文简介正在准备中。当前显示原文说明。
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
中文简介正在准备中。当前显示原文说明。
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
中文简介正在准备中。当前显示原文说明。
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
中文简介正在准备中。当前显示原文说明。