配置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
相关产品推荐
相关产品推荐

