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

配置OmitOnRecursionBehavior后仍遇AutoFixture循环引用问题求助

解决AutoFixture循环引用异常(已配置OmitOnRecursionBehavior仍触发)

问题背景

已在测试类构造函数中配置OmitOnRecursionBehavior,但使用AutoData属性创建Workspace实例时仍触发循环引用异常,测试代码如下:

[UsesVerify]
public class UpdateWorkspaceTests : TestBase
{
    private readonly Fixture _fixture;
    public UpdateWorkspaceTests()
    {
        _fixture = new Fixture();
        _fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b => _fixture.Behaviors.Remove(b));
        _fixture.Behaviors.Add(new OmitOnRecursionBehavior(1));
    }

    [Theory, AutoData]
    public async Task UpdateWorkspace_ValidUpdate_OnUpdatedEvent(Workspace workspace)
    {     
        _dbContextMock.Setup(x => x.Set<Workspace>()).ReturnsDbSet(new List<Workspace> { workspace });
        _dbContextFactoryMock.Setup(f => f.CreateDbContextAsync(It.IsAny<CancellationToken>()))
                            .ReturnsAsync(_dbContextMock.Object);

        var request = new UpdateWorkspaceInput(
            workspace.Id,
            "Workspace2 - New Name",
            "Workspace2 - Description"
            );

        var handler = new UpdateWorkspaceHandler(_dbContextFactoryMock.Object, _eventSenderMock.Object);
        Workspace? updatedWorkspace = await handler.Handle(request, _cancellationToken);

        _eventSenderMock.Verify(
              mock => mock.SendAsync(
                  nameof(WorkspaceSubscriptions.OnUpdatedWorkspace),
                  updatedWorkspace,
                  _cancellationToken),
              Times.Once);
    }
}

异常路径显示Organization→User→OrganizationUser→Organization形成循环,导致AutoFixture抛出ObjectCreationExceptionWithPath。

核心原因

测试方法使用的[AutoData]属性会独立创建新的Fixture实例,而非复用测试类构造函数中配置好的_fixture,因此递归行为仍为默认的ThrowingRecursionBehavior,你的配置并未生效。

解决方案

1. 自定义AutoDataAttribute复用配置

创建自定义属性,让AutoData使用你配置好的Fixture:

public class CustomAutoDataAttribute : AutoDataAttribute
{
    public CustomAutoDataAttribute()
        : base(() =>
        {
            var fixture = new Fixture();
            // 移除默认的递归抛出行为
            fixture.Behaviors.RemoveAll(b => b is ThrowingRecursionBehavior);
            // 设置忽略递归的层级
            fixture.Behaviors.Add(new OmitOnRecursionBehavior(1));
            return fixture;
        })
    {
    }
}

修改测试方法的属性:

[Theory, CustomAutoData]
public async Task UpdateWorkspace_ValidUpdate_OnUpdatedEvent(Workspace workspace)
{
    // 测试逻辑不变
}

2. 调整递归忽略层级

如果当前设置的层级(1)不足以覆盖对象图的深度,可以提高层级值:

// 在自定义AutoDataAttribute中修改
fixture.Behaviors.Add(new OmitOnRecursionBehavior(2));

更大的层级值会让AutoFixture在更深的嵌套中才忽略循环引用,避免提前触发异常。

3. 手动忽略循环关联属性

针对异常路径中的循环属性,直接让AutoFixture忽略它们,简化对象图:

// 在自定义AutoDataAttribute的Fixture配置中添加
fixture.Customize<Organization>(c => c.Without(o => o.Users));
fixture.Customize<User>(c => c.Without(u => u.OrganizationUser));
fixture.Customize<OrganizationUser>(c => c
    .Without(ou => ou.Organization)
    .Without(ou => ou.User));

4. 手动创建实例避免AutoFixture自动生成循环

如果测试不需要完整的对象图,可以手动创建Workspace实例,避免AutoFixture遍历循环引用:

[Theory]
public async Task UpdateWorkspace_ValidUpdate_OnUpdatedEvent()
{
    // 手动创建最简Workspace实例
    var workspace = new Workspace
    {
        Id = _fixture.Create<Guid>(),
        Name = _fixture.Create<string>(),
        Description = _fixture.Create<string>()
        // 忽略循环关联的Organization等属性
    };

    // 剩余测试逻辑不变
    _dbContextMock.Setup(x => x.Set<Workspace>()).ReturnsDbSet(new List<Workspace> { workspace });
    // ...
}

内容的提问来源于stack exchange,提问作者kumar425

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:34:59