基本目录结构:
我一直在尝试将测试代码保持在要测试的代码旁边,实际上是在同一个目录中,文件名与带有正在测试的代码的文件略有不同。到目前为止,我喜欢这种方法。这样的想法是,您不必花费时间和精力来使目录结构在您的代码和测试代码之间保持同步。因此,如果您更改代码所在目录的名称,则无需查找并更改测试代码的目录名称。这也使您花费更少的时间查找与某些代码一起的测试代码,因为它就在旁边。这样一来,创建带有测试代码的文件就不再那么麻烦了,因为您不必首先查找带有测试的目录,可能会创建一个新目录以匹配您要为其创建测试的目录,然后创建测试文件。您只需在此处创建测试文件。
这样的一个巨大优势是,这意味着其他员工(不是您,因为您永远不会这样做)将不太可能避免编写测试代码,因为这太繁琐了。即使将方法添加到现有类中,由于查找测试代码的摩擦较小,它们也不太可能不会喜欢将测试添加到现有测试代码中。
一个缺点是,这使得在没有附带测试的情况下更难以发布生产代码。尽管如果使用严格的命名约定,则仍然有可能。例如,我一直在使用ClassName.php,ClassNameUnitTest.php和ClassNameIntegrationTest.php。当我想运行所有的单元测试时,有一个套件可以查找以UnitTest.php结尾的文件。集成测试套件的工作原理与此类似。如果需要,我可以使用类似的技术来防止测试发布到生产环境。
这种方法的另一个缺点是,当您只查找实际代码而不是测试代码时,需要花费更多的精力来区分两者。但是我觉得这实际上是一件好事,因为它迫使我们感到现实的痛苦,即测试代码也是代码,它增加了自己的维护成本,并且与其他任何东西一样,都是至关重要的一部分,而不是其他任何东西。只是东西偏向某处。
每班一个测试班:
对于大多数程序员来说,这还远不是实验性的,但是对我来说是这样。我正在尝试每个测试类只有一个测试类。过去,每个要测试的类都有一个完整的目录,然后在该目录中有几个类。每个测试类都以某种方式设置要测试的类,然后有很多方法,每个方法都有不同的断言。但是后来我开始注意到某些条件,我会将这些对象放入与从其他测试类进入的其他条件相同的东西。重复变得难以处理,因此我开始创建抽象来删除它。测试代码变得非常难以理解和维护。我意识到了这一点,但是我看不到对我有意义的替代方法。在每个类中只有一个测试类似乎似乎无法测试几乎足够的情况,而又无法将所有这些测试代码都包含在一个测试类中。现在,我对此有不同的看法。即使我是对的,对于其他想要编写和维护测试的程序员和我本人来说,这也是一个巨大的缓冲。现在,我正在尝试强迫自己在每个要测试的类中拥有一个测试类。如果我在一个测试类中遇到太多无法测试的事情,我正在尝试将其视为一种迹象,表明所测试的类做得太多,应该分成多个类。为了消除重复,我尝试尽可能地坚持更简单的抽象,以使所有内容都存在于一个可读的测试类中。
更新
我仍在使用和喜欢这种方法,但是我发现了一种很好的技术,可以减少测试代码和重复代码的数量。在测试类本身内部编写可重用的断言方法非常重要,该类中的测试方法经常使用这些方法。如果我认为它们是内部DSL,它可以帮助我提出正确类型的断言方法(Bob叔叔提倡的东西,实际上他实际上是在提倡内部DSL提倡)。有时,您可以通过接受具有简单值的字符串参数来进一步扩展此DSL概念(实际上是DSL),该值表示您要执行的测试类型。例如,有一次我制作了一个可重用的声明方法,该方法接受$ left,$ comparesAs和$ right参数。$this->assertCmp('a', '<', 'b')
。
老实说,我不能太强调这一点,这是使编写测试具有可持续性(您和其他程序员希望继续做)的全部基础。这使测试所增加的价值超过了他们所获得的价值。关键不是您需要使用那种确切的技术,而是要使用某种可重用的抽象,这些抽象允许您编写简短易读的测试。似乎我正在从这个问题中脱颖而出,但实际上并非如此。如果不这样做,最终将陷入陷入陷阱的陷阱,即需要为每个要测试的类创建多个测试类,然后事情就会真正崩溃。