Agent skill
testing-xunit
Use when writing unit tests, integration tests, or setting up test projects in C#. Covers xUnit patterns, Moq mocking, Bogus test data generation, and Alba integration testing.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/testing-xunit
SKILL.md
xUnit Testing
Apply these patterns when writing tests in .NET projects.
Required Packages
<PackageReference Include="xunit" Version="2.*" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.*" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
<PackageReference Include="Moq" Version="4.*" />
<PackageReference Include="Bogus" Version="35.*" />
<PackageReference Include="Alba" Version="8.*" /> <!-- Integration tests -->
Project Structure
tests/
├── MyApp.UnitTests/
│ ├── GlobalUsings.cs
│ ├── Fakers/UserFaker.cs
│ └── Services/UserServiceTests.cs
└── MyApp.IntegrationTests/
└── Endpoints/UserEndpointsTests.cs
GlobalUsings.cs:
global using Xunit;
global using Moq;
global using Bogus;
Test Naming
Pattern: MethodName_Scenario_ExpectedResult
GetByIdAsync_WithValidId_ReturnsUser()
GetByIdAsync_WithInvalidId_ReturnsNull()
CreateAsync_WithDuplicateEmail_ThrowsValidationException()
Test Structure
[Fact]
public async Task GetByIdAsync_WithValidId_ReturnsUser()
{
// Arrange
var expectedUser = new UserFaker().Generate();
_mockRepo.Setup(r => r.GetByIdAsync(expectedUser.Id)).ReturnsAsync(expectedUser);
// Act
var result = await _sut.GetByIdAsync(expectedUser.Id);
// Assert
Assert.NotNull(result);
Assert.Equal(expectedUser.Name, result.Name);
}
Test Data with Bogus
public sealed class UserFaker : Faker<User>
{
public UserFaker()
{
RuleFor(u => u.Id, f => f.IndexFaker + 1);
RuleFor(u => u.Email, f => f.Internet.Email());
RuleFor(u => u.FirstName, f => f.Name.FirstName());
RuleFor(u => u.IsActive, true);
}
public UserFaker AsInactive()
{
RuleFor(u => u.IsActive, false);
return this;
}
}
var user = new UserFaker().Generate();
var users = new UserFaker().Generate(10);
var inactiveUser = new UserFaker().AsInactive().Generate();
Mocking with Moq
public class UserServiceTests
{
private readonly Mock<IUserRepository> _mockRepo;
private readonly UserService _sut;
public UserServiceTests()
{
_mockRepo = new Mock<IUserRepository>();
_sut = new UserService(_mockRepo.Object);
}
}
// Setup
_mockRepo.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(new User { Id = 1 });
_mockRepo.Setup(r => r.GetByIdAsync(It.IsAny<int>())).ReturnsAsync(new User());
_mockRepo.Setup(r => r.GetByIdAsync(-1)).ThrowsAsync(new ArgumentException());
// Verify
_mockRepo.Verify(r => r.GetByIdAsync(1), Times.Once);
_mockRepo.Verify(r => r.DeleteAsync(It.IsAny<int>()), Times.Never);
Integration Testing with Alba
public class UserEndpointsTests : IAsyncLifetime
{
private IAlbaHost _host = null!;
public async Task InitializeAsync()
{
_host = await AlbaHost.For<Program>(builder =>
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IUserRepository, FakeUserRepository>();
});
});
}
public async Task DisposeAsync() => await _host.DisposeAsync();
[Fact]
public async Task GetUser_WithValidId_ReturnsOk()
{
await _host.Scenario(_ =>
{
_.Get.Url("/api/users/1");
_.StatusCodeShouldBeOk();
});
}
[Fact]
public async Task CreateUser_WithValidData_ReturnsCreated()
{
var newUser = new UserFaker().Generate();
var result = await _host.Scenario(_ =>
{
_.Post.Json(newUser).ToUrl("/api/users");
_.StatusCodeShouldBe(HttpStatusCode.Created);
});
var created = await result.ReadAsJsonAsync<User>();
Assert.Equal(newUser.Email, created.Email);
}
}
Shared Host with Collection Fixture
public class AppFixture : IAsyncLifetime
{
public IAlbaHost Host { get; private set; } = null!;
public async Task InitializeAsync() => Host = await AlbaHost.For<Program>();
public async Task DisposeAsync() => await Host.DisposeAsync();
}
[CollectionDefinition("App")]
public class AppCollection : ICollectionFixture<AppFixture> { }
[Collection("App")]
public class UserEndpointsTests
{
private readonly IAlbaHost _host;
public UserEndpointsTests(AppFixture fixture) => _host = fixture.Host;
}
Test Attributes
[Fact] // Single test case
[Theory] // Parameterized
[InlineData(2, 3, 5)]
[InlineData(0, 0, 0)]
public void Add_TwoNumbers_ReturnsSum(int a, int b, int expected)
{
Assert.Equal(expected, Calculator.Add(a, b));
}
[Theory]
[MemberData(nameof(GetTestCases))]
public void Process_WithTestCases_ReturnsExpected(User input, bool expected) { }
[Trait("Category", "Unit")] // Run with: dotnet test --filter "Category=Unit"
Assertions
Assert.Equal(expected, actual);
Assert.NotNull(obj);
Assert.True(condition);
Assert.Empty(collection);
Assert.Contains(item, collection);
Assert.Single(collection);
Assert.Throws<ArgumentException>(() => DoSomething());
await Assert.ThrowsAsync<InvalidOperationException>(() => DoSomethingAsync());
Assert.IsType<User>(result);
Requirements
- One assertion focus per test
- Use
MethodName_Scenario_Expectednaming - Keep tests independent with no shared mutable state
- Use Bogus for realistic test data
- Mock external dependencies only
- Test edge cases: null, empty, boundaries
- Use Theory for data variations
- Use Alba for integration tests
Do not test implementation details. Do not mock the system under test. Do not use Thread.Sleep. Do not share mutable test data.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?