基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/rudironsoni/Synaxis --skill dotnet-xunit命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
AI-powered wiki generation for code repositories with commands, agents, and skills
Routes .NET/C# work to domain skills. Loads coding-standards for code paths.
Skill manifest management for dotnet-agent-harness. Tracks skill dependencies, conflicts, version compatibility, and provides validation and resolution tools. Triggers on: skill manifest, dependency resolution, skill compatibility, version conflicts, build manifest, validate dependencies.
| name | dotnet-xunit |
| description | Authors xUnit v3 tests -- Facts, Theories, fixtures, parallelism, IAsyncLifetime. |
| metadata | {"short-description":".NET skill guidance for xunit tasks"} |
xUnit v3 testing framework features for .NET. Covers [Fact] and [Theory] attributes, test fixtures (IClassFixture,
ICollectionFixture), parallel execution configuration, IAsyncLifetime for async setup/teardown, custom assertions,
and xUnit analyzers. Includes v2 compatibility notes where behavior differs.
Version assumptions: xUnit v3 primary (.NET 8.0+ baseline). Where v3 behavior differs from v2, compatibility notes are provided inline. xUnit v2 remains widely used; many projects will encounter both versions during migration.
Prerequisites: Test project already scaffolded via [skill:dotnet-add-testing] with xUnit packages referenced. Run [skill:dotnet-version-detection] to confirm .NET 8.0+ baseline for xUnit v3 support.
Cross-references: [skill:dotnet-testing-strategy] for deciding what to test and how, [skill:dotnet-integration-testing] for combining xUnit with WebApplicationFactory and Testcontainers.
| Feature | xUnit v2 | xUnit v3 |
|---|---|---|
| Package | xunit (2.x) | xunit.v3 |
| Runner | xunit.runner.visualstudio | xunit.runner.visualstudio (3.x) |
| Async lifecycle | IAsyncLifetime | IAsyncLifetime (now returns ValueTask) |
| Assert package | Bundled | Separate xunit.v3.assert (or xunit.v3.assert.source for extensibility) |
| Parallelism default | Per-collection | Per-collection (same, but configurable per-assembly) |
| Timeout | Timeout property on [Fact] and [Theory] | Timeout property on [Fact] and [Theory] (unchanged) |
| Test output | ITestOutputHelper | ITestOutputHelper (unchanged) |
[ClassData] | Returns IEnumerable<object[]> | Returns IEnumerable<TheoryDataRow<T>> (strongly typed) |
[MemberData] | Returns IEnumerable<object[]> | Supports TheoryData<T> and TheoryDataRow<T> |
| Assertion messages | Optional string parameter on Assert methods | Removed in favor of custom assertions (v3.0); use Assert.Fail() for explicit messages |
v2 compatibility note: If migrating from v2, replace xunit package with xunit.v3. Most [Fact] and [Theory]
tests work without changes. The primary migration effort is in IAsyncLifetime (return type changes to ValueTask),
[ClassData] (strongly typed row format), and removed assertion message parameters.
[Fact] -- Single Test CaseUse [Fact] for tests with no parameters:
public class DiscountCalculatorTests
{
[Fact]
public void Apply_NegativePercentage_ThrowsArgumentOutOfRangeException()
{
var calculator = new DiscountCalculator();
var ex = Assert.Throws<ArgumentOutOfRangeException>(
() => calculator.Apply(100m, percentage: -5));
Assert.Equal("percentage", ex.ParamName);
}
[Fact]
public async Task ApplyAsync_ValidDiscount_ReturnsDiscountedPrice()
{
var calculator = new DiscountCalculator();
var result = await calculator.ApplyAsync(100m, percentage: 15);
Assert.Equal(85m, result);
}
}
```text
### `[Theory]` -- Parameterized Tests
Use `[Theory]` to run the same test logic with different inputs.
#### `[InlineData]`
Best for simple value types:
```csharp
[Theory]
[InlineData(100, 10, 90)] // 10% off 100 = 90
[InlineData(200, 25, 150)] // 25% off 200 = 150
[InlineData(50, 0, 50)] // 0% off = no change
[InlineData(100, 100, 0)] // 100% off = 0
public void Apply_VariousInputs_ReturnsExpectedPrice(
price, percentage, expected)
{
calculator = DiscountCalculator();
result = calculator.Apply(price, percentage);
Assert.Equal(expected, result);
}
```text
Best complex data shared datasets:
```csharp
{
TheoryData<Order, > ValidationCases => ()
{
{ Order { Items = [(, )], CustomerId = }, },
{ Order { Items = [], CustomerId = }, },
{ Order { Items = [(, )], CustomerId = }, },
};
[]
[]
{
validator = OrderValidator();
result = validator.IsValid(order);
Assert.Equal(expected, result);
}
}
```text
Best data shared across multiple test classes:
```csharp
: <<, , >>
{
IEnumerator<TheoryDataRow<, , >> GetEnumerator()
{
;
;
;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
[]
[]
{
converter = CurrencyConverter();
rate = converter.GetRate(, to);
Assert.Equal(expectedRate, rate, precision: );
}
```text
---
Fixtures provide shared, expensive resources across tests maintaining test isolation.
{
ConnectionString { ; ; } = ;
{
ConnectionString = ;
ValueTask.CompletedTask;
}
{
ValueTask.CompletedTask;
}
}
: <>
{
DatabaseFixture _db;
{
_db = db;
}
[]
{
repo = OrderRepository(_db.ConnectionString);
result = repo.GetByIdAsync(KnownOrderId);
Assert.NotNull(result);
}
}
```text
**v2 compatibility note:** In xUnit v2, `IAsyncLifetime.InitializeAsync()` `DisposeAsync()` `Task`. In v3, they `ValueTask`. When migrating, change the types accordingly.
Use multiple test classes need the same expensive resource:
```csharp
[]
: <>
{
}
[]
{
DatabaseFixture _db;
{
_db = db;
}
[]
{
}
}
[]
{
DatabaseFixture _db;
{
_db = db;
}
}
```text
For per-test setup/teardown without a shared fixture:
```csharp
:
{
_tempDir = ;
{
_tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(_tempDir);
ValueTask.CompletedTask;
}
{
(Directory.Exists(_tempDir))
Directory.Delete(_tempDir, recursive: );
ValueTask.CompletedTask;
}
[]
{
filePath = Path.Combine(_tempDir, );
File.WriteAllTextAsync(filePath, );
processor = FileProcessor();
records = processor.ProcessAsync(filePath);
Assert.Equal(, records.Count);
}
}
```text
---
xUnit runs test classes within a collection sequentially but runs different collections parallel. Each test `[]` , .
###
####
:
```
[("", = )]
{ }
[]
{
}
```text
Create `xunit.runner.json` the test project root:
```json
{
: ,
: ,
: ,
:
}
```text
Ensure it copied to output:
```xml
<ItemGroup>
<Content Include= CopyToOutputDirectory= />
</ItemGroup>
```json
**v2 compatibility note:** In v2, configuration was via `xunit.runner.json` assembly attributes. v3 retains `xunit.runner.json` support the same property names.
---
Capture diagnostic output that appears test results:
```csharp
{
ITestOutputHelper _output;
{
_output = output;
}
[]
{
sw = Stopwatch.StartNew();
result = processor.ProcessBatchAsync(largeDataset);
sw.Stop();
_output.WriteLine();
Assert.True(sw.Elapsed < TimeSpan.FromSeconds());
}
}
```text
Bridge xUnit output to `Microsoft.Extensions.Logging` integration tests:
```csharp
:
{
ITestOutputHelper _output;
=> _output = output;
=>
XunitLogger(_output, categoryName);
{ }
}
{
IDisposable? BeginScope<TState>(TState state) TState : => ;
=> ;
{
output.WriteLine();
(exception )
output.WriteLine(exception.ToString());
}
}
```text
---
Create domain-specific assertions cleaner test code:
```csharp
{
{
Assert.NotNull(order);
(order.Status != expected)
{
Xunit.Sdk.EqualException.ForMismatchedValues(
expected, order.Status);
}
}
{
Assert.NotNull(order);
item = Assert.Single(order.Items, i => i.Sku == sku);
Assert.Equal(quantity, item.Quantity);
}
}
[]
{
order = Order();
order.Complete();
OrderAssert.HasStatus(order, OrderStatus.Completed);
}
```text
Group related assertions so all are evaluated even one fails:
```csharp
[]
{
order = OrderFactory.Create(request);
Assert.Multiple(
() => Assert.Equal(, order.CustomerId),
() => Assert.Equal(OrderStatus.Pending, order.Status),
() => Assert.NotEqual(Guid.Empty, order.Id),
() => Assert.NotEmpty(order.Items)
);
}
```text
**v2 compatibility note:** `Assert.Multiple` xUnit v3. In v2, use separate assertions -- the test stops at the first failure.
---
The `xunit.analyzers` package (included xUnit v3) catches common test authoring mistakes at compile time.
| Rule | Description | Severity |
|------|-------------|----------|
| `xUnit1004` | Test methods should be skipped | Info |
| `xUnit1012` | Null should be used type parameters | Warning |
| `xUnit1025` | `InlineData` should be unique within a `Theory` | Warning |
| `xUnit2000` | Constants literals should be the expected argument | Warning |
| `xUnit2002` | Do use check type | Warning |
| `xUnit2007` | Do use `` expression to check type | Warning |
| `xUnit2013` | Do use equality check to check collection size | Warning |
| `xUnit2017` | Do use `Contains()` to check exists a | Warning |
In `.editorconfig` test projects:
```ini
[]
dotnet_diagnostic.xUnit1004.severity = suggestion
```csharp
---
- **One fact per `[Fact]`, one concept per `[Theory]`.** If a `[Theory]` tests fundamentally different scenarios, split separate `[Fact]` methods.
- **Use `IClassFixture` expensive shared resources** within a single test . Use `ICollectionFixture` multiple classes share the same resource.
- **Do disable parallelism globally.** Instead, tests that share mutable state named collections.
- **Use `IAsyncLifetime` setup/teardown** instead of constructors `IDisposable`. Constructors cannot be , `IDisposable.Dispose()` does .
- **Keep test data close to the test.** Prefer `[InlineData]` simple cases. Use `[MemberData]` `[ClassData]` only data complex shared.
- **Enable xUnit analyzers** all test projects. They common mistakes that lead to -passing flaky tests.
---
**Do use constructor-injected `ITestOutputHelper` methods.** `ITestOutputHelper` per-test-instance; store it an instance field, a one.
**Do forget to make fixture classes ``.**
Primary approach: Use Serena symbol operations for efficient code navigation:
serena_find_symbol instead of text searchserena_get_symbols_overview for file organizationserena_find_referencing_symbols for impact analysisserena_replace_symbol_body for clean modificationsWhen to use Serena vs traditional tools:
Example workflow:
# Instead of:
Read: src/Services/OrderService.cs
Grep: "public void ProcessOrder"
# Use:
serena_find_symbol: "OrderService/ProcessOrder"
serena_get_symbols_overview: "src/Services/OrderService.cs"