c# - Moq 设置返回对对象的引用
问题描述
假设我有一个名为 MyRequestHandler 的简单类,它有一个名为 ProcessRequest 的方法,该方法只接受一个请求对象,将其映射到返回对象并返回该对象。(这显然是我正在研究的更复杂的方法/测试的一个非常简单的示例)。
public class MyRequestHandler
{
private IMapper _mapper;
public MyRequestHandler(IMapper maper)
{
_mapper = mapper;
}
public MyReturnObject ProcessRequest(MyRequestObject requestObject)
{
MyReturnObject returnObject = _mapper.Map<MyReturnObject>(requestObject);
return returnObject;
}
}
现在对于单元测试(使用 Xunit),我想测试 ProcessRequest 方法,但显然想要 Moq Map 方法,如下所示:
MyRequestObject requestObject = new RequestObject()
{
RequestInt = 1,
RequestString = "Hello"
};
MyReturnObject returnObject = new MyReturnObject()
{
MyInt = 1,
MyString = "Hello"
};
Mock<IMapper> mockMapper = new Mock<IMapper>();
mockMapper.Setup(m => m.Map<MyRequestObject>(requestObject)).Returns(returnObject);
MyRequestHandler requestHandler = new MyRequestHandler(mockMapper.Object);
MyReturnObject response = requestHandler.ProcessRequest(requestObject);
Assert.Equal(returnObject.MyInt, response.MyInt);
Assert.Equal(returnObject.MyString, response.MyString);
这里的问题是 Moq 返回(我想应该很明显它是)对 returnObject 的引用,所以我的断言将始终通过,即使我的方法要在返回对象之前更改值。现在我可以在 Moq Setup/Return 中实例化一个新的 MyReturnObject 并通过我给新的值比较 MyInt 和 MyString,但是如果它是一个非常复杂的对象,有 20 个属性和对象列表怎么办?也许我想使用 AutoFixture 创建要返回的对象并使用 DeepEqual 来比较它们?这甚至可能吗?我是不是看错了,还是我必须在设置/返回中进行某种类型的克隆才能使其正常工作?
解决方案
我不相信有内置功能来检测被测方法没有改变传递给它的对象。
选项:
- 确保返回对象是不可变的——要么让它们一开始就不可变,要么返回没有“set”方法的接口,并使用通过模拟创建的实例
- 为“预期”和“模拟”值创建单独的实例,然后逐个比较属性。有很多帮助库可以做到这一点(我喜欢 FluentAssertions)。
- 只需断言单个属性而不是比较对象 - 适用于少量字段。
如果可能的话,我更喜欢不可变对象 - 防止编写错误代码的可能性,从而减少所需的测试量。
推荐阅读
- r - 如果满足条件,则计数行
- arduino - Arduino 预处理器在定义术语 WIFI_AP 和 WIFI_STA 时行为不端
- vba - VBA 代码在 3 台机器中的 2 台上运行良好 - 不知道为什么
- sql - SQL:WHERE 子句中的 CASE 语句
- windows - Windbg ProcessUptime 不等于内核时间 + 用户时间
- java - 保护 Spring Boot 2 API
- java - Java VM 参数类型 -D 和 --
- netsuite - 有没有办法将联系人的类别与他们的角色联系起来?
- powershell - 获取消息历史
- python - Pandas:将季度数据转换为月度数据