使用FakeItEasy伪造LINQ查询转字典时遇‘非伪造对象’错误
问题:FakeItEasy配置LINQ链式调用时抛出“未识别为假对象”错误
要测试的生产代码逻辑:从数据库查询指定物种的动物,按Code去重后生成字典
var animals = _dataService.Query<Animal>() .Where(x => x.Species == 2) .GroupBy(i => i.Code) .Select(i => i.FirstOrDefault()) .ToDictionary(i => i.Code, i => i);
原测试代码配置:
// Arrange var fakeIDataService = A.Fake<IDataService>(); var fakeMapper = A.Fake<IMapper>(); var monkey = new Animal { Id = 1, Description = "Monkey", Code = "MKY", Species = 2 }; var animals = new Dictionary<string, Animal>() { { monkey.Code, monkey} }; A.CallTo(() => fakeIDataService.Query<Animal>() .Where(x => x.Species == 2) .GroupBy(i => i.Code) .Select(i => i.FirstOrDefault()) .ToDictionary(i => i.Code, i => i) ).Returns(animals); // Act var service = new ProcessAnimalLines(fakeIDataService, fakeMapper); // Assert A.CallTo(() => fakeIDataService.SaveChangesAsync()).MustHaveHappened(Repeated.Exactly.Once);
运行测试时抛出错误:
System.ArgumentException : The specified object is not recognized as a fake object.
错误原因
FakeItEasy只能拦截**假对象(Fake)**上的方法调用,而Query<Animal>()返回的IQueryable<Animal>/IEnumerable<Animal>是真实的集合类型(不是Fake对象),无法被FakeItEasy捕获后续的LINQ链式调用(Where/GroupBy等),因此配置整个LINQ链的返回会触发报错。
正确测试写法
应该只FakeQuery<Animal>()方法,让它返回预先构造好的测试数据集合,然后让真实的LINQ逻辑执行去重生成字典,这样既符合生产代码逻辑,又能正确完成测试:
// Arrange var fakeIDataService = A.Fake<IDataService>(); var fakeMapper = A.Fake<IMapper>(); // 构造测试数据,包含重复Code的动物,模拟去重场景 var testAnimals = new List<Animal> { new Animal { Id = 1, Description = "Monkey", Code = "MKY", Species = 2 }, new Animal { Id = 2, Description = "Duplicate Monkey", Code = "MKY", Species = 2 }, new Animal { Id = 3, Description = "Tiger", Code = "TGR", Species = 2 } }; // 仅Fake Query方法,返回测试集合(如果返回IQueryable则用AsQueryable转换) A.CallTo(() => fakeIDataService.Query<Animal>()).Returns(testAnimals.AsQueryable()); // Act var service = new ProcessAnimalLines(fakeIDataService, fakeMapper); service.Process(); // 调用服务中执行目标逻辑的方法 // Assert A.CallTo(() => fakeIDataService.SaveChangesAsync()).MustHaveHappened(Repeated.Exactly.Once);
说明
- 这种方式测试的是真实的业务逻辑(去重生成字典),而不是跳过LINQ逻辑直接返回结果,测试更准确。
- 如果生产代码中
Query<Animal>()返回的是IEnumerable<Animal>,直接返回testAnimals即可,无需AsQueryable()。
内容的提问来源于stack exchange,提问作者Bruno Pugioli
相关产品推荐
相关产品推荐

