为何AutoFixture自定义后不同属性返回同一实例?
关于AutoFixture中同类型属性生成同一实例问题的原因分析
这问题我之前排查过好几次,核心和AutoFixture的实例复用逻辑以及自定义配置的细节脱不了干系,咱们逐个场景拆解:
1. 简易自定义导致的实例复用
AutoFixture默认的行为是:每次请求一个类型的实例时,都会生成全新的对象——但如果你的自定义配置不小心把类型的创建逻辑变成了「单例模式」,就会触发所有请求都返回同一个实例的问题。
举个典型的错误案例:如果你的自定义代码是这样写的:
// 错误:提前创建好列表,所有请求都返回同一个引用 var preCreatedList = new List<string>(); fixture.Register(() => preCreatedList);
这种情况下,不管AutoFixture要生成多少个List<string>实例,都会拿到同一个preCreatedList的引用,自然你的两个同类型属性会指向同一个列表。
正确的做法应该是把对象创建逻辑放在委托内部,确保每次请求都生成新实例:
// 正确:每次请求都创建新的列表 fixture.Register(() => new List<string>());
2. 使用CreateMany<string>(3).ToList()导致的失败
这个场景的问题本质和上面类似——很多人会犯的错误是:提前执行ToList()并把结果缓存起来,然后注册成返回这个缓存的实例。比如:
// 错误:只生成一次带3个元素的列表,所有请求复用它 var fixedLengthList = fixture.CreateMany<string>(3).ToList(); fixture.Register(() => fixedLengthList);
哪怕你用了CreateMany,只要是提前生成好列表再返回,结果还是同一个引用。
正确的写法是让委托每次都重新执行CreateMany和ToList:
// 正确:每次请求都生成新的、带3个元素的列表 fixture.Register(() => fixture.CreateMany<string>(3).ToList());
另外提一句,AutoFixture 4.0对集合的生成策略做了调整,相比3.50.7会更严格地检查实例复用的场景,所以同样的错误在4.0中更容易暴露出来。
3. 额外的排查建议
如果你不确定问题出在哪,可以在测试中打印两个属性的GetHashCode()或者直接比较引用:
var sut = fixture.Create<YourClass>(); Console.WriteLine(sut.List1.GetHashCode()); Console.WriteLine(sut.List2.GetHashCode()); Console.WriteLine(ReferenceEquals(sut.List1, sut.List2)); // 正常应该是false
如果输出True,那肯定是实例复用的问题,回头检查你的自定义注册逻辑就行。
内容的提问来源于stack exchange,提问作者xlecoustillier
相关产品推荐
相关产品推荐

