Unit testing 模拟单元测试中的行为。为什么验证方法调用是有益的?

Unit testing 模拟单元测试中的行为。为什么验证方法调用是有益的?,unit-testing,mocking,Unit Testing,Mocking,我看到很多开发人员编写这样的单元测试: [TestMethod] public void AddTrainer_InvokesProviderAddTrainer() { //安排 var trainerBusiness=新的trainerBusiness(_trainerProviderMock.Object); //表演 trainerBusiness.AddTrainer(新用户配置文件()); //断言 _trainerProviderMock.Verify(v=>v.AddTraine

我看到很多开发人员编写这样的单元测试:

[TestMethod]
public void AddTrainer_InvokesProviderAddTrainer()
{
//安排
var trainerBusiness=新的trainerBusiness(_trainerProviderMock.Object);
//表演
trainerBusiness.AddTrainer(新用户配置文件());
//断言
_trainerProviderMock.Verify(v=>v.AddTrainer(It.IsAny()),Times.one);
}
我理解正在发生的事情,我只是不太清楚这将解决什么问题。这里的测试证明业务对象中的
AddTrainer
方法正在调用提供者中的
AddTrainer
方法

只要正确添加了培训师,商业方法如何进行对我来说有什么重要性?对我来说,这意味着如果我们决定要改变商业方法在未来添加培训师的方式,即使培训师仍然在添加,这个单元测试失败,我们必须重写它

在我看来,这种类型的测试只是确认没有人改变你的方法,有点像校验和,而不是确认任何有用的行为


我缺少什么?

这是为了确保没有人干扰
TrainersBusiness.AddTrainer
方法,方法是添加一些条件,防止
UserProfile
添加到
TrainerProvider
在void返回方法的单元测试中经常看到这一点,因为人们不知道该怎么做断言。有时这是个好主意,有时只是为了获得高代码覆盖率。我认为您的示例属于代码范围。对我来说,关键是“It.IsAny”用法与测试方法的名称相结合。作者可以将其命名为AddTrainer_GetCodeCoverage。如果您有两个名为AddTrainer_ValidTrainer_InvokesProviderAddTrainer和AddTrainer_InvalidTrainer_ThrowSpecificExeception的测试,每个测试都对模拟进行不同的检查并确认传递给模拟的值,那么您就有了一些有价值的东西

@George:这是一个关于一种常见做法的问题,一开始似乎并不直观,我不明白为什么要关闭它。@Jeroenvanevel问题的内容不是问题;问题在于问题的写作方式,“重点是什么?”“我为什么要关心?”“我为什么要给猴子一个怎么做的答案?”这导致了辩论模式,而不是“可以解决的问题”模式。当然,更不用说,关于堆栈溢出有很多问题:我稍微改变了措辞。它可能已经关闭了,但潜在的问题是“从单元测试的角度来看,这个验证告诉了我什么”,这是一个公平的问题。如果是重复的,那当然是一个很好的理由,但就目前情况而言,我认为这个问题是可以回答的。@George:我确实搜索了以前的问题,但他们似乎只是认为测试行为是一件好事。我不明白为什么测试一件事情是如何实现的,会在测试它已经实现的基础上增加一个好处。最后一句话对我很有意义。我可以看到在不同的情况下测试代码的正确路径的好处。但是如果他们真的弄乱了它,让培训师以其他方式加入,不是吗?这里的测试不应该是培训师是否已添加,而不是如何添加的吗?假设UserProfile的属性为IsExternal,如果要求仅由非管理员的用户添加此标志设置为true的配置文件,则管理员应允许添加此项。现在,如果有人实现了这个逻辑来检查AddTrainer方法中的IsExternal,这将是一个错误,并且可以通过这个测试检测到。因此,该测试有助于加强该方法的单一责任。