Alc*_*nja 17
许多模拟框架正在将模拟和存根的概念更接近和接近,以至于它们在功能上几乎可以被认为是相同的.但是,从概念的角度来看,我通常会尝试遵循这个惯例:
当您确保每个单元测试仅测试一件事时,这将变得更加清晰.当然,如果您尝试在一次测试中测试所有内容,那么您也可以期待一切.但是,只考虑特定单元测试所检查的内容,您的代码就更清晰了,因为您可以一目了然地看到测试的目的是什么.
这样做的另一个好处是,当更改导致中断时,您将更加不受更改影响并获得更好的错误消息.换句话说,如果你微妙地改变你的实现的某些部分,你更有可能只打破一个测试用例,这将显示你到底发生了什么,而不是一整套测试打破和只是创造噪音.
编辑:基于一个人为的例子可能会更清楚,其中计算器对象审计数据库的所有添加(伪代码)...
public void CalculateShouldAddTwoNumbersCorrectly() {
var auditDB = //Get mock object of Audit DB
//Stub out the audit functionality...
var calculator = new Calculator(auditDB);
int result = calculator.Add(1, 2);
//assert that result is 3
}
public void CalculateShouldAuditAddsToTheDatabase() {
var auditDB = //Get mock object of Audit DB
//Expect the audit functionality...
var calculator = new Calculator(auditDB);
int result = calculator.Add(1, 2);
//verify that the audit was performed.
}
Run Code Online (Sandbox Code Playgroud)
因此,在第一个测试用例中,我们正在测试Add方法的功能,并不关心审计事件是否发生,但我们碰巧知道计算器不能使用auditDB引用,所以我们只是将它存根为我们提供最少的功能,以使我们的特定测试用例正常工作.在第二个测试中,我们专门测试当你做一个Add,审计事件发生时,所以我们在这里使用期望(注意我们甚至不关心结果是什么,因为那不是我们正在测试的).
是的,您可以将两个案例合并为一个,并做出预期并断言您的结果为3,但是您在一个单元测试中测试了两个案例.这会使你的测试变得更脆弱(因为有更大的表面区域可能会改变以打破测试)并且不太清楚(因为当合并的测试失败时,它不是立即明显的问题是什么...是添加不起作用,或审核无效?)
“预期操作,存根查询”。如果调用应该改变被测对象之外的世界状态,那就让它成为一种期望——你关心它是如何被调用的。如果它只是一个查询,你可以在不改变系统状态的情况下调用它一次或六次,然后存根调用。
还有一件事,请注意存根和期望之间的区别,即单个调用,不一定是整个对象。