使用xUnit和AutoFixture时延迟初始化属性被意外访问
问题:AutoFixture注入InitOnce时单元测试失败的原因与解决办法
复现用的极简类
public class InitOnce<T> where T : struct { private T? _value; public T DefaultValue { get; set; } public T Value => _value ??= DefaultValue; }
测试需求
需要验证以下两点:
- 首次访问
Value属性时,它会被初始化为DefaultValue的当前值。 - 后续对
DefaultValue的修改会被忽略,不会影响已初始化的Value。
对应的测试逻辑如下,预期能通过:
private static void RunTest(InitOnce<int> initOnce) { initOnce.DefaultValue = 1; Assert.Equal(1, initOnce.Value); initOnce.DefaultValue = 2; Assert.Equal(1, initOnce.Value); }
测试现状
显式创建实例的测试(通过)
如果在测试体内显式通过AutoFixture的Build API创建实例,测试可以正常通过:
[Theory] [AutoData] public void Test1(IFixture fixture) { InitOnce<int> initOnce = fixture.Build<InitOnce<int>>().OmitAutoProperties().Create(); RunTest(initOnce); // PASS }
直接注入实例的测试(失败)
尝试用[NoAutoProperties]特性直接注入InitOnce<int>实例以消除样板代码时,测试意外失败:
[Theory] [AutoData] public void Test2([NoAutoProperties] InitOnce<int> initOnce) { RunTest(initOnce); // FAIL - why? }
失败的错误信息:
Assert.Equal() Failure: Values differ
Expected: 1
Actual: 0
显然,在RunTest将DefaultValue从0改为1之前,已经有操作访问了Value属性,导致它提前被初始化为0。
环境信息
使用的.NET版本为8.0,相关NuGet包版本如下:
<PackageReference Include="AutoFixture.Xunit2" Version="4.18.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="xunit" Version="2.9.2" /> <PackageReference Include="xunit.runner.visualstudio" Version="3.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference>
疑问
这是什么原因导致的?如何修改才能让Test2通过?
内容的提问来源于stack exchange,提问作者Michael Liu
相关产品推荐
相关产品推荐

