dim*_*414 6 language-agnostic unit-testing design-patterns anti-patterns
我正在开发一个个人项目(意思是干净的源代码,没有遗留的依赖项),并尝试遵循有关单元测试,依赖关系管理等的最佳实践.
我公司的代码库充满了这样的代码:
public Response chargeCard(CreditCard card, Money amount) {
if(Config.isInUnitTests()) {
throw new IllegalStateException("Cannot make credit card API calls in unit tests!");
}
return CreditCardPOS.connect().charge(card, amount);
}
Run Code Online (Sandbox Code Playgroud)
这里的目标是主动防止在测试期间执行具有外部依赖性的危险代码/代码.如果单元测试做坏事我喜欢快速失败的概念,但我不喜欢这个实现有几个原因:
Config整个代码库中分散的静态类留下了隐藏的依赖关系.我可以通过更好的依赖感知来避免在我公司的代码库中使用它的相当多的地方,我试图这样做,但仍然有一些地方我仍然在努力去实现一种isInUnitTests()方法.
使用上面的信用卡示例,我可以isInUnitTests()通过在一个可模拟的CardCharger类或类似的东西中正确地将它包装起来来避免对每次充电的检查,但是虽然我觉得我只是将问题提升到一个级别 - 如何做我阻止单元测试构建一个真实的实例CardCharger而不检查创建它的构造函数/工厂方法?
isInUnitTests()一个代码味道?为了澄清,我试图阻止单元测试访问不可接受的资源,如数据库或网络.我喜欢依赖注入的测试友好模式,但如果粗略的开发人员(即我)可能会违反好模式,那么好的模式就没用了 - 在单元测试做事情的情况下,对我来说快速失败似乎很重要不应该,但我不确定最好的方法.
IsInUnitTests()是一个代码味道吗?
是的,确切地说,您有很多方法可以避免将代码与单元测试结合起来.没有正当理由拥有这样的东西.
如果是这样,我怎么能继续强制单元测试不能达到外部依赖?
您的测试必须仅验证代码单元并为外部依赖项创建模拟或存根.
你的代码似乎是Java,它有很多成熟的模拟框架.研究一下现有的,然后挑选一个更喜欢你的人.
编辑
如何在不对创建它的构造函数/工厂方法进行检查的情况下,阻止单元测试构建HTTPRequest的实例
您应该使用依赖注入器来解析您的实例依赖关系,这样您就不需要使用a if来测试您是否正在进行测试,因为在您的"真实"代码中您注入了完整的功能依赖关系并且在您的测试中注入模拟或存根.
举一个更严肃的例子,比如信用卡充电器(经典的单元测试示例) - 如果测试代码甚至可以访问真正的卡充电器而不会引发大量异常,那么这似乎是一个非常糟糕的设计.在这样的情况下,我认为仅仅相信开发人员会做正确的事情是不够的
再次,你应该注入外部依赖作为信用卡充电器,所以在你的测试中你会注入一个假的.如果一些开发人员不知道这一点,我认为贵公司需要的第一件事就是为开发人员提供培训,并使用一些编程来指导流程.
在任何情况下,我都明白你的意思,让我告诉你我遇到的类似情况.
有一个应用程序在经过一些处理之后发送了一堆电子邮件.除了直播之外,这些电子邮件不会发送到任何其他环境,否则这将是一个大问题.
在我开始研究这个应用程序之前,开发人员曾多次"忘记"这个规则,并且在测试环境中发送了电子邮件,导致了很多问题.依靠人类记忆来避免这种问题并不是一个好的策略.
我们为避免再次发生这种情况所做的是添加配置设置以指示是否发送真实的电子邮件.正如您所看到的,问题比在单元测试中执行或不执行更广泛.
但是,没有什么可以替代通信,开发人员可以在他的开发环境中为此设置设置不正确的值.你永远不会百分百安全.
简而言之:
IsInUnitTest为因为问题比这更广泛(您还希望避免在开发人员计算机上执行此逻辑)| 归档时间: |
|
| 查看次数: |
278 次 |
| 最近记录: |