安装xUnit需同时引入xunit、xunit.runner.visualstudio和Microsoft.NET.Test.Sdk三个包;[Fact]用于单点验证,[Theory]需配合[InlineData]等数据源;资源初始化用构造函数或IClassFixture,清理用IDisposable;Assert.Equal对复杂对象需自定义比较器或用FluentAssertions;并行执行默认开启,须避免共享状态。

怎么装xUnit并让测试跑起来
直接在测试项目里装两个包就行:xunit 和 xunit.runner.visualstudio。缺后者的话,Visual Studio 的 Test Explorer 里根本看不到测试方法,命令行跑也会报“找不到测试运行器”。
常见错误现象:
- 写了
[Fact]却在 Test Explorer 里不显示 → 没装xunit.runner.visualstudio或没引用Microsoft.NET.Test.Sdk - dotnet test 报错 “No test is available” → csproj 里缺少
<istestproject>true</istestproject>属性
推荐一步到位的命令:
dotnet add package xunit<br>dotnet add package xunit.runner.visualstudio<br>dotnet add package Microsoft.NET.Test.Sdk
[Fact] 和 [Theory] 到底该用哪个
[Fact] 是固定输入、固定预期的单点验证;[Theory] 是参数化测试的入口,必须配合 [InlineData] 或 [MemberData] 才能运行。
容易踩的坑:
- 只写
[Theory]不加任何数据源 → 测试会被忽略,且不报错,静默失败 - 把
[InlineData]里的类型写错(比如传string却期望int)→ 运行时报System.ArgumentException: Object of type 'System.String' cannot be converted to type 'System.Int32' - 想复用 Setup 逻辑,却在
[Theory]构造函数里做耗时操作 → 每个参数组合都会新建实例,重复执行
示例对比:
[Fact]<br>public void Add_2_and_3_returns_5() { Assert.Equal(5, new Calculator().Add(2, 3)); }<br><br>[Theory]<br>[InlineData(2, 3, 5)]<br>[InlineData(-1, 1, 0)]<br>public void Add_ReturnsCorrectSum(int a, int b, int expected) {<br> Assert.Equal(expected, new Calculator().Add(a, b));<br>}
测试类里怎么初始化和清理资源
xUnit 不支持 [SetUp] 和 [TearDown],它靠构造函数 + IDisposable 或 IClassFixture<t></t> 控制生命周期。
使用场景:
- 每个测试都要新对象?→ 直接写在构造函数里(每次测试都新建实例)
- 数据库连接、HTTP 客户端等开销大的共享资源?→ 用
IClassFixture<databasefixture></databasefixture>,整个测试类只初始化一次 - 需要释放非托管资源(如文件句柄、socket)?→ 让测试类实现
IDisposable,Dispose()里写清理逻辑
性能影响:滥用 IClassFixture 可能让本该隔离的测试互相干扰;而全靠构造函数又可能拖慢大量测试的启动速度。
为什么 Assert.Equal 失败却不告诉你具体值
默认的 Assert.Equal(expected, actual) 在失败时只提示“Expected: 5, Actual: 4”,但如果你传的是自定义对象或复杂结构,它可能只输出 MyType 而不是字段值——因为没重写 ToString() 或没开启详细比较。
解决办法:
- 对简单类型(
int、string、DateTime)放心用Assert.Equal - 对对象比较,改用
Assert.Equal(expected, actual, new MyEqualityComparer())或直接换FluentAssertions:actual.Should().BeEquivalentTo(expected) - 调试时临时加
_output.WriteLine(actual.ToString())(需注入ITestOutputHelper)
别忘了:xUnit 默认不捕获 Console.WriteLine,要用 ITestOutputHelper 才能在 Test Explorer 里看到输出。
最常被忽略的一点:xUnit 的并行执行是默认开启的,如果你的测试偷偷读写静态字段、共享文件或共用内存缓存,结果会随机失败——这种问题不会在本地复现,只在 CI 上爆发。


















