gpt4 book ai didi

unit-testing - 像 isInUnitTest() 这样的检查是反模式吗?

转载 作者:行者123 更新时间:2023-12-04 05:11:54 25 4
gpt4 key购买 nike

我正在从事一个个人项目(意味着干净的源代码,没有遗留依赖项)并尝试遵循有关单元测试、依赖项管理等的最佳实践。

我公司的代码库中到处都是这样的代码:

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);
}

这里的目标是主动防止在测试期间执行危险代码/具有外部依赖关系的代码。如果单元测试做错事,我喜欢快速失败的概念,但我不喜欢这个实现有几个原因:
  • 它将隐藏的依赖关系留给散布在我们代码库中的静态 Config 类。
  • 它改变了测试和实时行为之间的控制流,这意味着我们不一定要测试相同的代码。
  • 它向配置文件或其他一些状态保持实用程序添加了外部依赖项。
  • 它看起来很丑:)

  • 通过更好的依赖意识可以避免我们在我公司的代码库中使用它的相当多的地方,我正在尝试这样做,但是仍然有一些地方我仍然在努力摆脱实现 isInUnitTests() 方法.

    使用上面的信用卡示例,我可以通过将其正确包装在一个可模拟的 isInUnitTests() 类或类似的东西中来避免对每笔费用进行 CardCharger 检查,但是虽然更干净,但我觉得我只是将问题提升了一个级别 -如何防止单元测试构造 CardCharger 的真实实例而不检查创建它的构造函数/工厂方法?
  • isInUnitTests() 是代码气味吗?
  • 如果是这样,我怎样才能仍然强制单元测试不达到外部依赖项?
  • 如果不是,实现这种方法的最佳方法是什么,何时使用/避免它的良好做法是什么?


  • 为了澄清,我试图阻止单元测试访问 Not Acceptable 资源,如数据库或网络。我完全支持像依赖注入(inject)这样的测试友好模式,但是如果一个粗心的开发人员(即我)可能违反它们,那么好的模式就毫无用处 - 在单元测试完成它们所要做的事情的情况下,快速失败对我来说似乎很重要不应该,但我不确定最好的方法。

    最佳答案

    Is isInUnitTests() a code smell?



    是的,毫无疑问,您有很多方法可以避免将代码耦合到单元测试。没有正当理由拥有这样的东西。

    If so, how can I still enforce that unit tests don't reach external dependencies?



    您的测试必须只验证一个代码单元并创建 mock or stubs对于外部依赖。

    您的代码似乎是 Java,其中包含大量成熟的模拟框架。研究一下现有的,然后选择更喜欢你的。

    编辑

    how do I prevent a unit test from constructing a real instance of HTTPRequest without putting a check in the constructor / factory method that creates it



    你应该使用依赖注入(inject)器来解决你的实例依赖,所以你永远不需要使用 if测试您是否在测试中,因为在“真实”代码上注入(inject)完整的功能依赖项,在测试中注入(inject)模拟或 stub 。

    Take a more serious example, like a credit card charger (a classic unit testing example) - it would seem like a very poor design if it were even possible for test code to access the real card charger without triggering a deluge of exceptions. I don't think it's enough in a case like that to trust the developer will always do the right thing



    同样,您应该注入(inject)外部依赖项作为信用卡充电器,因此在您的测试中您将注入(inject)一个假的。如果某些开发人员不知道这一点,我认为贵公司需要的第一件事是为该开发人员进行培训,并进行一些结对编程来指导该过程。

    无论如何,我明白你的意思,让我告诉你我经历过的类似情况。

    有一个应用程序经过一些处理后发送了一堆电子邮件。这些邮件不能在除了live之外的任何其他环境中发送,否则会是个大问题。

    在我开始开发这个应用程序之前,有好几次开发人员“忘记”了这个规则,并且在测试环境中发送了电子邮件,导致了很多问题。依靠人类内存来避免此类问题并不是一个好的策略。

    为了避免这种情况再次发生,我们所做的是添加一个配置设置来指示是否发送真实的电子邮件。如您所见,问题比在单元测试中执行或不执行更广泛。

    但是,没有什么可以替代通信,开发人员可能会在他的开发环境中为此设置设置不正确的值。你永远不会 100% 安全。

    简而言之:
  • 第一道防线是沟通和培训。
  • 你的第二道防线应该是依赖注入(inject)。
  • 如果您觉得这还不够,您可以添加第三道防线:配置设置以避免在测试/开发环境中执行真正的逻辑。没有错。但请不要命名IsInUnitTest因为问题比这更广泛(您还希望避免在开发人员机器上执行此逻辑)
  • 关于unit-testing - 像 isInUnitTest() 这样的检查是反模式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17904236/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com