【发布时间】:2019-03-20 23:37:50
【问题描述】:
假设您有以下方法要测试:
public void foo(object myObject, bool myBool)
{
if(myBool)
repositoryA.save(myObject)
else
repositoryB.save(myObject)
}
对此类函数进行单元测试的最佳方法是什么?如果你写 2 个测试 当 myBool 为 true 时调用 assert repositoryA,当 myBool 为 false 时调用 repositoryB,那么对函数的以下更改仍会使测试通过,但可能会破坏应用程序的功能:
public void foo(object myObject, bool myBool)
{
repositoryA.save(myObject)
repositoryB.save(myObject)
}
另一方面,如果您断言当 myBool 为 true 时调用 repositoryA 并且不调用 repositoryB,这让您更有信心对函数的任何更改都不会引入错误,但是您有一个测试取决于实现细节。最好的方法是什么?
如果您使用 TDD,您会编写哪些测试以达到所需的功能?
【问题讨论】:
-
如果您测试其中一个存储库被调用并发现正常,那么调用存储库不是实现细节。因此,测试不调用存储库并不是测试实现细节。也就是说:测试不应该涵盖某人可以在代码中做的所有潜在的奇怪事情。如果您发现潜在的破损有合理的可能性发生,则添加该断言。否则,不要。但请记住,破坏测试的开发人员也可能会更改测试代码。 bast 调用可能有两种方法,而不是一种。
-
谢谢,有道理
-
也许不是你的情况,因为你的例子有点“不完整”;我的意思是:有一个更好的命名可以帮助这篇论文。无论如何:您的实现似乎隐藏了多态性(我指的是改变内部行为的布尔参数)。所以,如果你问我“如果你使用 TDD”,我会回答你说有这样的合同有点奇怪。我认为您可以对同一个 Repository 接口有两种不同的实现。但是,我真的不知道“myBool”是什么,所以这可能是一个合理的案例。
-
我无法修改合同,在我的情况下,我实际上有 9-10 个参数,每个参数都会影响我需要做的事情,坚持 repoA,坚持 repoB,调用 web api,什么都不做,因为它的逻辑实际上真的很复杂。我用一个简化的例子问了这个问题。
-
测试行为而不是实现。这样你就可以在不改变测试的情况下改变实现——自信地重构。 TDD 将帮助您以可测试、行为驱动的方式设计代码。
标签: unit-testing testing tdd