假设您制作了一个应用程序,试图将字母 A 中的内容尽可能地音译为字母 B。
因为语言 B 非常复杂,所以这并不总是成功的。但是你确实得到了一个近似的音译。
考虑到您预计 20-30% 会失败,在这种情况下您将如何构建单元测试?
假设您制作了一个应用程序,试图将字母 A 中的内容尽可能地音译为字母 B。
因为语言 B 非常复杂,所以这并不总是成功的。但是你确实得到了一个近似的音译。
考虑到您预计 20-30% 会失败,在这种情况下您将如何构建单元测试?
单元测试的成功必须始终是目标。您使用它的方式,您无法区分软件中的严重错误和您似乎期望的翻译错误。
我建议将两者分开:
单元测试应该是确定性的。失败的测试应该表明软件失败,而不是“按预期工作”。对于您的情况,以您可以确定结果的方式准备数据并对其进行测试,无论转换成功还是失败(测试失败始终是一种选择,因为您期望失败- 重要的是您始终可以控制何时您的测试通过/失败)。
预期会失败的单元测试不是单元测试。您需要通过使用充当过滤器并确定它是否“足够接近”并确定通过/失败的评估函数来更改成功的定义。随着您的翻译变得更好,您可以提高过滤器的标准。
我在这种情况下学到的一种技术是只测试代码中功能性(或确定性)的部分。当然,如果要从非确定性部分中分离出确定性部分,则是困难的部分。简写方式是“减少 [或重构] 为功能性”,这意味着分离出确定性的代码部分,然后测试这些部分。
有关基于场景的上下文,请阅读这篇关于在围绕遗留代码进行测试时应用该技术的博客文章(并使用名为ApprovalTests的开源单元测试库)。
这里可能感兴趣的另一种技术是“基于理论的”测试。有关更多信息,请查看此博客文章。
单元测试可能失败的唯一原因是是否涉及计时(主要是在测试电子设备的情况下)。但是,即使在这些情况下,目标也应该是从单元测试中消除计时问题,例如,如果可能的话,通过延长/切换超时或其他计时问题。当不可能时,应该有很好的记录。
消除时序问题并使测试具有确定性的另一种方法是使用某种注入方法为所有外部接口编写存根,即能够设置外部接口方法将返回的值。通过以这种方式设置单元测试,您可以从字面上测试所有内容以及每个错误条件。
(故事:我在一家公司工作,偶尔会有几个单元测试失败。只有少数人能够分析这些是严重错误还是时间问题。首先做好单元测试会节省很多时间) .