我正试图了解单元测试的实践。我读过单元测试不应该依赖于实现。
我理解这一点的方式是,例如,如果我们有一个函数int addTwoNumbers (int a, int b)
,我们应该测试,例如加法是否返回正确的结果(即addTwoNumbers (2, 2) == 4)
(,而不应该关心,例如,addTwoNumbers
是否只调用operator +
一次——它还不如对此使用位操作。
对我来说,这似乎是合理的,而且在我看来,它提供了测试和代码之间的良好解耦。
进入模拟框架。从阅读他们的文档中我可以看出,他们的功能相当于
(a( 生成实现基类(存根(和的某些接口的占位符功能的对象
(b( 检查是否根据测试人员提出的期望调用了该功能。
我对(a(没有问题——我知道我们有时需要硬编码一些外部依赖项的功能来进行测试。但我不明白,为什么我们要检查测试代码是否以测试人员期望的方式调用了mock的功能。
难道我们不应该只对测试方法返回的内容或它如何修改out参数感兴趣,而不关心它的实现细节吗?mocking框架的验证功能是否没有在测试代码和测试代码之间引入紧密耦合?
我不明白,为什么我们要检查测试代码是否以测试人员期望的方式调用mock的功能
因为方法的约定并不总是返回某些内容或修改其参数。有时合同的方法是(或包括(有副作用。以以下方法为例:
void notifyServerOfError(error: string) {
this.http.post('/api/errors', {
error: error,
ip: myIpAddress
});
}
此方法不返回任何内容。它不会修改其参数。它的唯一责任是将包含特定详细信息的特定对象发送到特定URL。因此,单元测试这种方法应该验证合同是否得到遵守。
一个很好的方法是模拟http
依赖关系,并检查在调用此方法时,其post()
方法是否确实使用正确的URL和正确的数据进行了调用。