You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:22:45