> Expect:这指定了一个嘲笑的方法应该返回的,并表示调用必须发生或测试失败(伴随着调用VerifyAllExpectationsHaveBeenMet()).
> Stub:这指定一个嘲笑的方法应该返回,但不能导致测试失败.
那么我该怎么办?
> Mock:只有当你明确地试图验证被测对象的行为(即你的测试是说这个对象必须调用该对象).
>存根:当你试图测试一些功能/行为,但是为了得到这个工作,你需要依赖一些外部对象(即你的测试是说这个对象必须做某些事情,但作为副作用,它可能调用该对象)
当您确保每个单元测试仅测试一件事情时,这将变得更加清晰.当然,如果您尝试在一个测试中测试所有内容,那么您也可以预期所有内容.但是,只要预期特定单元测试正在检查的内容,您的代码就会更清楚,因为您可以一目了然地看到测试的目的是什么.
这样做的另一个好处是,你将会更容易地与变化和当更改导致中断时,获取更好的错误消息.换句话说,如果你微妙地改变了你的实现的一部分,你更有可能只得到一个测试用例的破坏,这将显示出什么是坏的,而不是一整套的测试破坏&只是创造噪音.
编辑:它可能会更清晰的基于一个有计划的例子,一个计算器对象审计数据库的所有添加(伪代码)…
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. }
所以在第一个测试用例中,我们测试了Add方法的功能.不关心审计事件是否发生,但是我们碰巧知道计算器将无法使用auditDB引用,所以我们只是将其存储起来,以给我们最少的功能来使我们的具体测试用例工作.在第二个测试中,我们专门测试当您执行添加时,会发生审计事件,所以在这里我们使用期望(注意,我们甚至不关心结果是什么,因为这不是我们正在测试的).
是的,你可以把这两种情况合并成一个,&做出预期并声称你的结果是3,但是你在一个单元测试中测试两个例子.这将使您的测试更脆弱(因为有更大的表面积可能会改变以破坏测试),而不太清楚(因为合并测试失败后,它不会立即显现出什么问题.还是审计不工作?)