macalbert/envilder/dotnet-testing

Claude Code and agent skill by macalbert/envilder

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Mandatory testing conventions for .NET (xUnit, AwesomeAssertions). Use for unit, integration, or acceptance tests with xUnit, Testcontainers, or Playwright.

Install

npx vskill@latest install macalbert/envilder/dotnet-testing

SKILL.md

Testing Conventions (.NET)

This skill defines the MANDATORY testing conventions for .NET projects. These are rules, not guidelines.


Documentation Rules

NO Comments Except AAA Markers
  • NEVER write XML summaries on test methods or test classes
  • NEVER write explanatory comments: code must be self-explanatory
  • Only `// Arrange`, `// Act`, `// Assert` comments are allowed in tests
  • The test name Should_X_When_Y already documents the intent

Libraries

CategoryLibraryPurpose
FrameworkxUnitTest framework
AssertionsAwesomeAssertionsFluent assertion syntax
SnapshotsVerify.XunitSnapshot / approval testing
MockingNSubstituteSpies, stubs, and mocks
Mocking (HTTP)WireMock.NetHTTP service mocking
Test data (fake)BogusRealistic fake data (Mother pattern)
Test data (dummy)AutoFixtureAutomatic dummy object generation
ContainersTestcontainersDocker containers in tests

Core Principles

1. AAA Pattern (Arrange – Act – Assert)

ALL tests MUST follow the AAA pattern, separated by inline comments.

Rules
  • Each phase MUST be separated with comments
  • Never mix phases
  • **Each comment (// Arrange, // Act, // Assert) appears AT MOST ONCE

per test**: if you need two actions or two asserts, write two tests

  • Act = one single invocation on the SUT. Multiple statements in Act only

if they are genuinely part of the same logical action (rare and exceptional). Two independent operations = two tests.

  • All assertions belong in Assert only. No .Should() in Arrange or Act.

If you need a precondition check, extract it to a separate test or use a guard clause that throws: not an assertion.

  • AAA markers are mandatory in ALL tests: including structural guards,

static completeness checks, and data validation tests. No exceptions.

  • No `if`, `switch`, or conditional logic inside Arrange, Act, or Assert
  • No `try/catch/finally` inside tests: use IAsyncLifetime or

IDisposable for teardown

  • No `// Act & Assert` combined blocks: Act and Assert are ALWAYS separate
  • For exceptions: act.Should().ThrowAsync<T>() (AwesomeAssertions)
  • Omit comment if section is empty
  • If a test needs branching, split it into separate tests
xUnit Example
csharp
[Fact(Timeout = CancellationTokenForTest.ShortTimeout)]
public async Task Should_CreateGroup_When_RequestIsValid()
{
// Arrange
var request = new CreateGroupRequest { Name = "Test Group" };
var command = new CreateGroupCommand(request);
// Act
var actual = await _sut.Handle(command, CancellationToken.None);
// Assert
actual.Should().NotBeNull();
actual.GroupId.Should().NotBeEmpty();
_repository.Received(1).AddGroup(Arg.Any<Group>());
}

2. Test Naming Convention
text
Should_{ExpectedBehavior}_When_{Condition}
Rules
  • PascalCase for both parts
  • NO natural language
  • NO vague names (Should_Work, TestHandler)
  • NO missing When clause
  • Method names only: xUnit uses [Fact] or [Theory], not description strings

3. Variable Naming (MANDATORY)
PurposeName
Subject under test_sut (field) or sut (local)
Expected valueexpected
Actual resultactual

Test Class Structure

csharp
public class CreateGroupCommandHandlerTests
{
private readonly Fixture _fixture;
private readonly IEnvilderRepository _repository;
private readonly CreateGroupCommandHandler _sut;
public CreateGroupCommandHandlerTests()
{
_fixture = new();
_repository = Substitute.For<IEnvilderRepository>();
_sut = new(_repository);
}
}

Exception Testing

Act and Assert MUST be separate.

✅ CORRECT
csharp
[Fact(Timeout = CancellationTokenForTest.ShortTimeout)]
public async Task Should_ThrowNotFound_When_GroupDoesNotExist()
{
// Arrange
_repository.GetByIdAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>())
.Returns((Group?)null);
// Act
var act = () => _sut.Handle(query, CancellationToken.None);
// Assert
await act.Should().ThrowAsync<NotFoundException>();
}
❌ FORBIDDEN
csharp
// Act & Assert ← NEVER
await Assert.ThrowsAsync<NotFoundException>(
() => _sut.Handle(query, CancellationToken.None));

Teardown & Cleanup

Never use `try/finally` in tests. Use framework mechanisms:

ScenarioMechanism
Async setup/teardownIAsyncLifetime (InitializeAsync / DisposeAsync)
Sync cleanupIDisposable (Dispose)
Shared fixtureIAsyncLifetime on collection fixture
csharp
public class MyTests : IAsyncLifetime
{
private (string Name, string? Value)[] _originalEnvValues = [];
public Task InitializeAsync()
{
_originalEnvValues = EnvVarNames
.Select(v => (Name: v, Value: Environment.GetEnvironmentVariable(v)))
.ToArray();
return Task.CompletedTask;
}
public Task DisposeAsync()
{
foreach (var (name, value) in _originalEnvValues)
{
Environment.SetEnvironmentVariable(name, value);
}
return Task.CompletedTask;
}
}

Verification Commands

ContextCommand
Unit testsdotnet test tests/sdks/dotnet/ --filter "Category!=Acceptance"
Acceptance (Docker)dotnet test tests/sdks/dotnet/
Format checkdotnet format src/sdks/dotnet/Envilder.sln --verify-no-changes

Completion Criteria

  • Test names follow Should_<Expected>_When_<Condition>
  • AAA markers present (except structural guards), each at most once
  • _sut/actual/expected used consistently
  • All mock interactions verified with .Received()
  • No try/catch/finally or control flow in test bodies
  • Tests run green: dotnet test
  • No format regressions: dotnet format --verify-no-changes

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
135
Repository forks
4
7-day trend score
25

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/macalbert/envilder/dotnet-testing/badge)](https://verified-skill.com/skills/macalbert/envilder/dotnet-testing)

Something wrong with this skill or its page? Tell us.