Answers:
不要将它们视为“破碎的单元测试”,因为它们不是。
它们是规范,您的程序不再支持这些规范。
不要认为它是“修复测试”,而是“定义新需求”。
测试应首先指定您的应用程序,而不是相反。
您不能说自己有一个可行的实现,直到您知道它可行。您不能说它有效,直到您对其进行测试。
其他一些注意事项可能会指导您:
Don't think of it as "fixing the tests", but as "defining new requirements".
您所描述的内容实际上可能并不是一件坏事,但它是测试发现的更深层问题的指针
随着系统的变化,我们发现自己花费更多的时间来修复损坏的测试。我们有单元测试,集成测试和功能测试。
如果您可以更改代码,并且测试不会中断,那对我来说将是可疑的。合法更改和错误之间的区别仅在于请求的事实,而测试定义了请求的内容(假定为TDD)。
数据已被硬编码。
测试中的硬编码数据是一件好事。测试只是伪造,而不是证明。如果计算过多,则测试可能是重言式的。例如:
assert sum([1,2,3]) == 6
assert sum([1,2,3]) == 1 + 2 + 3
assert sum([1,2,3]) == reduce(operator.add, [1,2,3])
抽象度越高,您就越接近算法,从而越接近将自动实现与其自身进行比较。
很少重复使用代码
与jUnits一样assertThat
,测试中代码的最佳重用是imho'Checks' ,因为它们使测试保持简单。除此之外,如果可以将测试重构为共享代码,则实际测试的代码也可能如此,从而将测试减少为测试重构基础的测试。
我也有这个问题。我改进的方法如下:
不要编写单元测试,除非它们是测试某些东西的唯一好方法。
我完全准备承认单元测试的诊断成本和修复时间最低。这使它们成为有价值的工具。问题是,随着里程数的变化,单元测试通常过于琐碎,不足以维持代码量。我在底部写了一个例子,看看。
在与该组件的单元测试等效的地方使用断言。断言具有很好的属性,可以在任何调试版本中始终对其进行验证。因此,您不是在单独的测试单元中测试“ Employee”类约束,而是通过系统中的每个测试用例有效地测试Employee类。断言还具有不错的属性,即它们不会像单元测试那样增加代码量(最终需要脚手架/模拟/任何方式)。
在有人杀死我之前:生产构建不应因断言而崩溃。而是,他们应该在“错误”级别登录。
作为对尚未考虑的人的警告,请勿在用户或网络输入中声明任何内容。这是一个巨大的错误™。
在我最新的代码库中,我明智地删除了在有明显断言机会的地方进行的单元测试。这大大降低了整体维护成本,使我变得更加快乐。
首选系统/集成测试,以针对所有主要流程和用户体验实施它们。极端情况可能不需要在这里。系统测试通过运行所有组件来验证用户端的行为。因此,系统测试的速度必然较慢,因此编写重要的测试(不要多也不少),您会遇到最重要的问题。系统测试的维护费用非常低。
请记住,关键是,由于您使用断言,因此每个系统测试将同时运行数百个“单元测试”。您还可以放心,最重要的那些可以多次运行。
编写可以进行功能测试的强大API。如果您的API过于难以自行验证功能组件,那么功能测试将很尴尬,并且(让我们面对现实)毫无意义。良好的API设计a)使测试步骤简单明了,b)产生清晰而有价值的断言。
功能测试是最难解决的问题,尤其是当您具有跨过程障碍进行一对多或(甚至更糟糕的是,哦,上帝)多对多通信的组件时。附加到单个组件的输入和输出越多,功能测试就越困难,因为您必须隔离其中的一个才能真正测试其功能。
关于“不要编写单元测试”的问题,我将举一个例子:
TEST(exception_thrown_on_null)
{
InternalDataStructureType sink;
ASSERT_THROWS(sink.consumeFrom(NULL), std::logic_error);
try {
sink.consumeFrom(NULL);
} catch (const std::logic_error& e) {
ASSERT(e.what() == "You must not pass NULL as a parameter!");
}
}
该测试的作者添加了七行内容,这些内容完全对最终产品的验证没有帮助。用户永远都不会看到这种情况,这是因为a)没有人应该在那里传递NULL(然后写一个断言)或b)NULL的情况会引起一些不同的行为。如果是(b),请编写一个实际验证该行为的测试。
我的理念是,我们不应测试实现工件。我们应该只测试任何可以视为实际输出的东西。否则,无法避免在单元测试(强制执行特定实现)和实现本身之间编写两倍的基本代码量。
重要的是要注意,这里有很好的单元测试候选人。实际上,甚至在某些情况下,单元测试是验证某件事的唯一适当方法,并且在这种情况下编写和维护这些测试具有很高的价值。在我的头上,该列表包括非平凡的算法,API中公开的数据容器以及看起来“复杂”的高优化代码(又名“下一个家伙可能会搞砸了”。)。
然后,我向您提供具体建议:明智地开始删除单元测试,以免问自己一个问题:“这是输出,还是我在浪费代码?” 您可能会成功地减少浪费时间的事情。
我相信其他人会提供更多的投入,但是以我的经验,这些是可以帮助您的一些重要事项: