xunit-tests
Configures and runs xUnit.net (xUnit v2 + v3) - current de facto .NET test framework with `[Fact]` for single tests + `[Theory]` + `[InlineData]`/`[ClassData]`/`[MemberData]` for parametrized; collection fixtures (`[Collection]`) + class fixtures (`IClassFixture`) for shared setup; output via `ITestOutputHelper`; parallel test config via assembly attribute. Use when working with .NET (C# / F# / VB.NET) on the modern test stack.
Install with skills.sh (any agent)
npx skills add testland/qa --skill xunit-testsxunit-tests
Overview
Per xunit.net (opens in new window):
xUnit.net is the current .NET test standard (used by .NET Foundation projects + Microsoft's own .NET runtime). v3 released 2024; v2 still widely used in production.
Step 1 - Install
dotnet new xunit -n MyProjectTests
# Or in existing project:
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
dotnet add package Microsoft.NET.Test.SdkStep 2 - First test
using Xunit;
public class CalculatorTests
{
[Fact]
public void Adds_TwoNumbers()
{
Assert.Equal(3, Calculator.Add(1, 2));
}
}Run: dotnet test. Verify: assert the run reports Passed! with the expected test count before proceeding; if it exits non-zero or discovers 0 tests, confirm the class is public, the method carries [Fact], and all three packages (xunit, xunit.runner.visualstudio, Microsoft.NET.Test.Sdk) are installed, then re-run.
Step 3 - Parametrized tests
Per xn-docs (opens in new window):
[Theory]
[InlineData(1, 2, 3)]
[InlineData(0, 0, 0)]
[InlineData(-1, 1, 0)]
public void Adds_VariousInputs(int a, int b, int expected)
{
Assert.Equal(expected, Calculator.Add(a, b));
}
// Class-based data source
public class AddTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { 1, 2, 3 };
yield return new object[] { 0, 0, 0 };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
[Theory]
[ClassData(typeof(AddTestData))]
public void Adds_FromClassData(int a, int b, int expected) { ... }
// Method-based
public static IEnumerable<object[]> AddCases =>
new List<object[]> {
new object[] { 1, 2, 3 },
new object[] { 0, 0, 0 },
};
[Theory]
[MemberData(nameof(AddCases))]
public void Adds_FromMemberData(int a, int b, int expected) { ... }Step 4 - Skip + traits
[Fact(Skip = "Requires staging DB")]
public void SkippedTest() { }
[Fact]
[Trait("Category", "Integration")]
public void IntegrationTest() { }
// Filter: dotnet test --filter "Category=Integration"Fixtures + parallelism
For per-test, class (IClassFixture), and collection (ICollectionFixture) shared setup, plus assembly-level parallel config, see references/fixtures-and-parallelism.md.
Step 5 - Output (ITestOutputHelper)
xUnit suppresses Console.WriteLine in tests. Use ITestOutputHelper:
public class TestsWithOutput {
private readonly ITestOutputHelper _output;
public TestsWithOutput(ITestOutputHelper output) { _output = output; }
[Fact]
public void LogsContext() {
_output.WriteLine("Test running at {0}", DateTime.UtcNow);
}
}Step 6 - Pair with FluentAssertions
result.Should().Be(42);
list.Should().HaveCount(3).And.Contain("alice");
result.Should().BeOfType<Success>().Which.Value.Should().Be(42);See fluentassertions. Note: FluentAssertions changed license in 2024 (paid commercial; free for OSS); v6 is the last fully-free version.
Step 7 - CI integration
- run: dotnet test --logger "trx;LogFileName=test-results.trx" \
--collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
- uses: codecov/codecov-action@v4
with: { files: ./coverage/coverage.opencover.xml }Worked example
A service team writes xUnit coverage for a UserService backed by a database. They scaffold with dotnet new xunit (Step 1), cover pure logic like Calculator.Add with the [Theory] of Step 3, and park a staging-only case with the skip of Step 4. The DB-backed classes share one DatabaseFixture via a [Collection("DbCollection")] (see references/fixtures-and-parallelism.md) so they run sequentially against the shared connection while pure-logic tests parallelize. Diagnostics go through ITestOutputHelper (Step 5), and CI runs the coverage command of Step 7. Result: fast parallel unit coverage plus serialized DB-backed tests sharing one fixture.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Console.WriteLine instead of ITestOutputHelper | Output suppressed | Use ITestOutputHelper (Step 5) |
Use [Theory] without data attribute | Test never runs | Always include [InlineData] etc. |
Shared mutable state in IClassFixture | Test order dependence | Per-test fresh state OR [Collection] synchronization |
| Skip parallel tuning at scale | Slow CI | Per-assembly + per-collection config (see references/fixtures-and-parallelism.md) |
Limitations
References
xUnit collections, fixtures, and parallel execution
View source (opens in new window)xUnit collections, fixtures, and parallel execution
Reference material for xunit-tests: shared setup via fixtures and how xUnit parallelizes work. Collections are the shared concept - they govern both fixture sharing and parallelization. Core authoring lives in the skill's SKILL.md.
Fixtures
// Per-test (default): xUnit creates a new test class instance per test
public class CalculatorTests {
private readonly Calculator _calc;
public CalculatorTests() { _calc = new Calculator(); }
// ...
}
// Class fixture: shared across all tests in a class
public class DatabaseFixture : IDisposable {
public DbConnection Connection { get; }
public DatabaseFixture() { Connection = OpenConnection(); }
public void Dispose() { Connection.Close(); }
}
public class UserTests : IClassFixture<DatabaseFixture> {
private readonly DatabaseFixture _fixture;
public UserTests(DatabaseFixture fixture) { _fixture = fixture; }
[Fact] public void TestsUser() { /* uses _fixture.Connection */ }
}
// Collection fixture: shared across multiple test classes
[CollectionDefinition("DbCollection")]
public class DbCollection : ICollectionFixture<DatabaseFixture> { }
[Collection("DbCollection")]
public class TestsA { ... }
[Collection("DbCollection")]
public class TestsB { ... } // shares the same DatabaseFixtureParallel execution
By default xUnit runs collections in parallel; tests in the same collection run sequentially.
// Disable parallelism for an assembly:
[assembly: CollectionBehavior(DisableTestParallelization = true)]
// Or per-collection:
[assembly: CollectionBehavior(MaxParallelThreads = 4)]Related skills
fluentassertions
Reference for FluentAssertions - the canonical .NET fluent-assertion library pairable with xUnit / NUnit / MSTest; provides `.Should()` extension API (`.Should().Be()`, `.Should().BeOfType()`, `.Should().Throw()`, `.Should().BeEquivalentTo()` for deep equality, `.Should().Satisfy()` for predicates, `.Should().BeApproximately()` for floats); rich failure messages with object structure visualization. Covers the v8 license change: v8+ is free for open-source and non-commercial use but requires a paid license for commercial use, while v7 remains fully open-source. Use when a .NET test project needs deep object comparison or better failure output than `Assert.X` gives, when assertions must survive a move between xUnit / NUnit / MSTest, or when picking between v7 and v8+ on license grounds.
mstest-tests
Configures and runs MSTest (now MSTest.TestFramework v3) - Microsoft's first-party .NET test framework with `[TestClass]` / `[TestMethod]` / `[DataRow]` / `[DynamicData]` attributes; `[ClassInitialize]` / `[ClassCleanup]` / `[TestInitialize]` / `[TestCleanup]` lifecycle; `TestContext` injection; tight Visual Studio + dotnet test integration. Use when working with .NET on a MSTest codebase, or in environments standardized on Microsoft toolchain.
nunit-tests
Configures and runs NUnit - JVM-style attribute-driven .NET test framework with `[Test]` / `[TestCase]` / `[TestCaseSource]` / `[Values]` / `[Random]` parametrize attributes; `[SetUp]` / `[TearDown]` / `[OneTimeSetUp]` / `[OneTimeTearDown]` lifecycle; categories for selective runs; constraint-model assertion API (`Assert.That(actual, Is.EqualTo(expected))`); parameterized fixtures via `[TestFixture]` typed args. Use when working with .NET on a NUnit codebase or preferring constraint-model assertions over xUnit's classic style.