当他们编写单元测试时(可能在代码之前),他们创建了一个以“When”开头的类.该名称描述了运行测试的场景(夹具).他们将通过代码为每个分支创建子类.该类中的所有测试都以“should”开头,并且在运行后测试代码的不同方面.因此,他们将有一种方法来验证每个模拟(DOC)是否被正确调用以及检查返回值(如果适用).我对这种方法有点困惑,因为它意味着每次测试都运行完全相同的执行代码,这看起来很浪费.我想知道是否有类似的技术,他们可能已适应.解释风格及其应该如何实施的链接将是很棒的.我听起来类似于我见过的一些BDD方法.
我还注意到他们已经将重复调用“执行”SUT转移到设置方法中.当它们期望异常时会导致问题,因为它们不能使用内置工具来执行检查(Python unittest的assertRaises).这也意味着将返回值存储为测试类的支持字段.他们还必须存储许多模拟作为支持领域.在类层次结构中,很难分辨每个模拟的配置.
他们还测试代码有点不同.它真正归结为他们认为的集成测试.他们嘲笑任何窃取背景的东西远离被测试的功能.这可能意味着同一类中的私有方法.我一直限制模拟可能影响测试结果的资源,例如数据库,文件系统或日期.我可以看到这种方法的一些价值.但是,现在使用它的方式,我可以看到它导致脆弱的测试(测试随着每次代码更改而中断).我担心,因为没有集成测试,在这种情况下,您可能会错误地使用第三方API,但您的单元测试仍然会通过.我想更多地了解这种方法.
所以,任何关于在哪里学习更多关于这些方法的资源都会很好.我不愿意放弃一个很好的学习机会,因为我不了解他们做事的方式.我还想停止关注这些方法的负面影响,看看它带来的好处.
如果我在第一段中正确地理解了你的解释,那就和我经常做的很相似. (取决于测试框架是否易于使用.许多模拟框架也不支持它,但像 Mockito这样的间谍框架做得更好.)例如,参见stack example here,它有一个共同的设置(向堆栈添加内容),然后是一堆独立的测试,每个测试都检查一件事. Here’s still another example,这次没有任何测试(@Test)修改公共夹具(@Before),但是每个测试都专注于检查一个应该发生的独立事物.如果测试非常集中,那么应该可以更改生产代码以使任何单个测试失败,而所有其他测试都通过(我最近在Unit Test Focus Isolation中写过).
主要思想是让每个测试检查一个特征/行为,这样当测试失败时,它更容易find out why it failed.更多示例请参阅this TDD tutorial并了解该样式.
我并不担心多次执行相同的代码路径,当运行一个测试需要一毫秒时(如果需要more than a couple of seconds to run all unit tests,则测试可能太大).根据你的解释,我更担心测试可能与实现过于紧密耦合,而不是功能,如果它是系统的,每个模拟都有一个测试.测试的名称可以很好地指示测试结构良好或多么脆弱 – 它是描述功能还是如何实现该功能.
关于模拟,一本好读的书是Growing Object-Oriented Software Guided by Tests.一个不应该模拟第三方API(你不拥有也不能修改的API),因为你已经提到的原因,但是应该创建一个对它的抽象更好适合使用它的系统的需要,并以您想要的方式工作.这种抽象需要与第三方API进行集成测试,但在使用抽象的所有测试中,您都可以模拟它.