Moq设置在单独的班级

时间:2015-12-04 23:55:41

标签: c# entity-framework unit-testing moq

我正在使用moq版本4.2来测试web api 2的一些控制器,其中EF作为ORM。由于很多测试都需要模拟IEntityRepository<User>所以我在一个名为TestHelper的单独类中使用静态方法来创建这样一个假存储库,以便我可以在需要的所有测试中调用此方法。这是静态方法:

internal static IEntityRepository<User> GetSingleUserMockRepository(User user, bool noTracking = true, params Expression<Func<User, object>>[] properties)
{
            var userRepository = new Mock<IEntityRepository<User>>();
            if (properties.Any())
                userRepository.Setup(x => x.GetSingleInclude(user.Key, noTracking, properties)).Returns(Task.FromResult(user));
            else
                userRepository.Setup(x => x.GetSingle(user.Key, noTracking)).Returns(Task.FromResult(user));

            return userRepository.Object;
}

我在这里没有显示其他方法细节,因为我们认为它们与我的问题无关。问题是在我的测试中调用这个静态方法并将返回的用户存储库传递给控制器​​时,测试将失败,因为它无法找到用户,即Setup没有工作!但是,如果我在我的测试中重复测试实现来创建模拟存储库作为局部变量;一切正常。

即,这不起作用(其中Devices是用户实体的导航属性,同样不认为此处的细节很重要),例如如果我将返回的userRepository传递给我的控制器,测试将失败。:

var userRepository = TestHelper.GetSingleUserMockRepository(user, true, x=> x.Devices);

但这有效,例如如果我只是在测试中使用局部变量并将userRepository.Object传递给我的控制器,一切都按预期工作:

var userRepository = new Mock<IEntityRepository<User>>();
userRepository.Setup(x => x.GetSingleInclude(user.Key, true, u => u.Devices)).Returns(Task.FromResult(user));

有人可以解释一下原因吗?我认为这两种方式是相同的,但显然不是在实践中。

1 个答案:

答案 0 :(得分:1)

这可能不是一个完整的答案(但是),但仍然很长时间以适应Stack Overflow评论。

当你这样做时:

userRepository.Setup(x => x.GetSingleInclude(user.Key, noTracking, properties)).Returns(...);

你说的是:当使用GetSingleIncludeuser.Key调用noTracking,特别是properties表达式数组时,Moq将返回你指定。

但是,如果Moq接到GetSingleInclude的调用,其中一个或多个参数等于您提供的值,则您的设置无关紧要,而Moq则返回默认值为null。 (如果您使用了MockBehavior.Strict,那么它会抛出一个异常,而不是默默地返回null,这对于理解这个问题会更有帮助。)

那么两个表达式树数组何时相等? 如果 Moq对数组使用默认的相等比较器,那么当它们是相同的数组实例时,它们只是“相等”。 如果 Moq使用了一些逐项比较,那么它将归结为每个表达式树是否等于引用(即相同的Expression<>实例)。无论如何,你可能会遇到麻烦。

问题是为什么它适用于另一种情况。当GetSingleInclude(表达式树)的数量很少时,properties是否有特殊的重载?

this question运行代码的结果是什么?

我说你可能遇到与线程 Mocking and verifying call to method containing an Expression<Func<T,bool>> parameter中相同的问题。