如果我对一个mock对象设置了期望值,那么它会在我正在测试的方法调用的私有方法中使用吗
本文关键字:方法 测试 调用 有方法 一个 mock 对象 如果 期望值 设置 | 更新日期: 2023-09-27 18:20:57
方法:
public void MethodToTest()
{
//Do something
var result = PrivateMethod();
}
private UserProfile PrivateMethod(RegisterModel model)
{
return _unitOfWork.Repository<UserProfile>().GetSingle(u => u.UserName == model.UserName);
}
测试:
public void Test()
{
var registerModel = new RegisterModel
{
UserName = "admin",
Password = "123456",
}
var userProfile = new UserProfile
{
UserId = 1,
UserName = "admin"
};
var unitMock = new Mock<IUnitOfWork>();
unitMock.Setup(x => x.Repository<UserProfile>().GetSingle(u => u.UserName == registerModel.UserName)).Returns(userProfile);
//Do the rest of the test
}
这里没有显示,但Unit of Work
被注入构造函数中,因此_unitOfWork
可以被模拟。事实上,Unit of Work
是在私有方法中使用的,这是否意味着即使我模拟了对象并期望该方法和返回值,它仍然会访问数据库?如果是,我该如何避免这种情况?我已经读到我应该将我的私有方法提取到一个sepearate类中,但它已经使用工作单元进行了抽象。
解决您的问题
更改
unitMock.Setup(x => x.Repository<UserProfile>().GetSingle(u => u.UserName == registerModel.UserName)).Returns(userProfile);
至
unitMock.Setup(x => x.Repository<UserProfile>().GetSingle(It.IsAny<Func<UserProfile,bool>>())).Returns(userProfile);
您提供给Moq的lambda表达式在逻辑上可能与您在生产代码中使用的表达式等效,但在引用上并不等效。这意味着正在调用GetSingle
方法,但Mock中的lambda表达式是,而不是测试单元中调用的表达式的.Equals()
或==
,因此Moq上设置的函数永远不会被调用。默认情况下,由于Moq截断了方法,所以您的私有方法返回null,因为.GetSingle(Func<T,bool>)
在被Moq截断时返回null。
为什么会发生这种情况
您可以通过在C#REPL中编写以下内容来看到这一点:
Func<bool> func1 = () => true;
Func<bool> func2 = () => true;
Console.WriteLine(func1 == func2);
// > False
Console.WriteLine(func1.Equals(func2));
// > False
我可以放心地假设您正确设置了_unitOfWork
,否则您将获得NullReferenceException
,而不是由于方法链接而导致方法返回null。
代码设计
您可以通过将GetProfileByUsername(string)
方法添加到存储库中来解决此问题,而不允许将lambda参数传递给方法。现在您的代码耦合也很差,所以我建议使用这种方法。UnitOfWork.Repository<UserProfile>().GetSingle(..)
违反了德米特定律。此外,您的类对IRepository<UserProfile>
有依赖关系,而不是对UnitOfWork
有依赖关系。因此,实际上,您应该嘲笑IRepository<UserProfile>
而不是UnitOfWork
,并将该Mock传递到类中。如果不是这样的话,那么您的测试单元可能有太多的责任,并且违反了SRP以及作为LoD:)
否,_unitOfWork
变为实例变量。因此,您的私有方法将使用该变量,它将在您提供给构造函数的实例上调用该方法。这可以是您的数据库实现,也可以是您模拟的类。