Agent-skills xunit-skill
install
source · Clone the upstream repo
git clone https://github.com/LambdaTest/agent-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/LambdaTest/agent-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/xunit-skill" ~/.claude/skills/lambdatest-agent-skills-xunit-skill && rm -rf "$T"
manifest:
xunit-skill/SKILL.mdsource content
xUnit.net Testing Skill
Core Patterns
Basic Test
using Xunit; public class CalculatorTests { private readonly Calculator _calc = new(); [Fact] public void Add_TwoPositiveNumbers_ReturnsSum() { Assert.Equal(5, _calc.Add(2, 3)); } [Fact] public void Divide_ByZero_ThrowsException() { Assert.Throws<DivideByZeroException>(() => _calc.Divide(10, 0)); } }
Theory (Parameterized)
[Theory] [InlineData(2, 3, 5)] [InlineData(-1, 1, 0)] [InlineData(0, 0, 0)] public void Add_ReturnsCorrectSum(int a, int b, int expected) { Assert.Equal(expected, _calc.Add(a, b)); } [Theory] [MemberData(nameof(GetTestData))] public void Add_WithMemberData(int a, int b, int expected) { Assert.Equal(expected, _calc.Add(a, b)); } public static IEnumerable<object[]> GetTestData() { yield return new object[] { 1, 2, 3 }; yield return new object[] { -1, -1, -2 }; } [Theory] [ClassData(typeof(CalculatorTestData))] public void Add_WithClassData(int a, int b, int expected) { Assert.Equal(expected, _calc.Add(a, b)); }
Assertions
Assert.Equal(expected, actual); Assert.NotEqual(unexpected, actual); Assert.True(condition); Assert.False(condition); Assert.Null(obj); Assert.NotNull(obj); Assert.Contains("sub", str); Assert.DoesNotContain("x", str); Assert.Empty(collection); Assert.Single(collection); Assert.Collection(list, item => Assert.Equal("first", item), item => Assert.Equal("second", item)); Assert.IsType<MyClass>(obj); var ex = Assert.Throws<ArgumentException>(() => Method()); Assert.Equal("message", ex.Message); Assert.InRange(value, 1, 10);
Shared Context (IClassFixture)
public class DatabaseFixture : IDisposable { public DbConnection Connection { get; } public DatabaseFixture() { Connection = new DbConnection("test"); } public void Dispose() { Connection.Close(); } } public class UserTests : IClassFixture<DatabaseFixture> { private readonly DatabaseFixture _fixture; public UserTests(DatabaseFixture fixture) { _fixture = fixture; } [Fact] public void GetUser_ReturnsUser() { var user = _fixture.Connection.Query<User>("SELECT * FROM Users LIMIT 1"); Assert.NotNull(user); } }
Constructor/Dispose (Per-Test Setup)
public class MyTests : IDisposable { private readonly MyService _service; public MyTests() { _service = new MyService(); } // SetUp public void Dispose() { _service.Cleanup(); } // TearDown [Fact] public void TestSomething() { Assert.True(_service.IsReady); } }
Anti-Patterns
| Bad | Good | Why |
|---|---|---|
with parameters | + | xUnit convention |
| Static state | | Test isolation |
No | Implement for cleanup | Resource management |
Setup: dotnet add package xunit xunit.runner.visualstudio Microsoft.NET.Test.Sdk
dotnet add package xunit xunit.runner.visualstudio Microsoft.NET.Test.SdkRun: dotnet test
or dotnet test --filter "FullyQualifiedName~Calculator"
dotnet testdotnet test --filter "FullyQualifiedName~Calculator"Deep Patterns
For advanced patterns, debugging guides, CI/CD integration, and best practices, see
reference/playbook.md.