Unit testing 后条件是单元测试的一种类型吗?

Unit testing 后条件是单元测试的一种类型吗?,unit-testing,design-by-contract,Unit Testing,Design By Contract,我正试图将一些契约式设计技术融入到我的编码风格中。后置条件在我看来很像嵌入式单元测试,我想知道我在这里的想法是正确的还是偏离了基础 Wikipedia将后置条件定义为“在某段代码执行后或在正式规范中的操作后必须始终为真的条件或谓词。后置条件有时使用代码本身中的断言进行测试” 这与您在直接验证状态(不使用模拟)的单元测试中所做的不是很相似吗 如果是这样的话: 1) 通过使用post条件,我现在不是在生产代码中嵌入了测试代码吗?这不是令人不快吗 2) 使用后条件是否应该改变单元测试的结构?我的第一个

我正试图将一些契约式设计技术融入到我的编码风格中。后置条件在我看来很像嵌入式单元测试,我想知道我在这里的想法是正确的还是偏离了基础

Wikipedia将后置条件定义为“在某段代码执行后或在正式规范中的操作后必须始终为真的条件或谓词。后置条件有时使用代码本身中的断言进行测试”

这与您在直接验证状态(不使用模拟)的单元测试中所做的不是很相似吗

如果是这样的话:

1) 通过使用post条件,我现在不是在生产代码中嵌入了测试代码吗?这不是令人不快吗

2) 使用后条件是否应该改变单元测试的结构?我的第一个想法是断言逻辑从测试转移到后条件。也就是说,测试将使用相同的输入,我仍然在测试我以前测试过的所有内容,但是现在我没有在单元测试中进行断言,而是对后条件是否通过进行简单的二进制断言

3) 我的第二个想法是,后置条件代码可能有控制流,因此对于测试代码来说并不理想,因为测试代码应该很简单并且避免控制流。但是,如果我测试后条件,那么我可以在单元测试中依赖它们吗

4) 测试后置条件似乎很困难,因为如果我理解正确,它们基本上是通过或失败的,你必须重复后置条件本身的逻辑来检查它是否做了正确的事情。那么,如何测试后置条件?您是否通过在单元测试中不使用它们来检查它们,并确保单元测试和后条件同时通过或失败


5) 我的单元测试有时会验证某个方法是否导致了协作者状态的更改。在标准实践中,后置条件是否包括协作者状态,或者仅仅包括定义它们的类的状态?

与任何方法或编码样式一样,没有单一的正确答案。然而,到目前为止,我发现一件事是正确的,那就是从来没有一个“一刀切”的解决方案

这样,如果在您的设计中将这些断言实现为每一个后置条件的逻辑,那么我认为这是错误的。 我个人的观点是,只有当不满足后条件导致整个系统处于危险的不一致状态时,才应该使用这种断言。因此,如果发生类似情况,我肯定希望系统执行类似操作:向管理员发送电子邮件/短信、停止生产执行、运行诊断或为特定系统执行任何操作。注意,这将是一个实际的特性,其目的是提高安全性,而不是单元测试代码


另一方面,如果您在每次方法调用之后编写断言,那么正如您所注意到的,您所做的唯一事情就是将测试用例硬编码到生产代码中。除了让你的代码库变得一团糟之外,这没有任何真正的目的。

契约不是单元测试的一种形式。相反,它们是一种指定(以可执行格式)在调用特定函数或方法之前和之后应保持什么条件的方法,还可以指定对象的不变量

当你有契约时,你仍然需要测试,因为仅仅因为你已经指定了函数应该做什么并不意味着它们实际上会做。但您会发现契约将帮助您进行调试,因为如果代码能够检查运行时发生的事情是否符合预期,则意味着任何逻辑或编程错误都会导致包含错误的代码附近出现故障

您可能会发现,使用契约,您会很高兴拥有更少的较小测试和更多的较大规模测试,因为契约将允许您缩小错误的来源,即使测试范围很广。此外,单元测试不太需要扮演逻辑应该如何工作的规范角色,这进一步限制了较小测试的价值


契约类似于断言,因为您可以选择在生产代码中启用或不启用它们。我的观点是,契约往往比断言更昂贵,因此在生产过程中往往会禁用它们。

您走的是正确的道路

确实,post条件的用途与单元测试类似。关键区别在于post条件始终运行,而单元测试仅针对已知数据集运行。这意味着post条件不太可能忽略您没有想到的拐角情况,但在运行时成本更高

以下是您具体问题的答案

  • 有一个运行时惩罚后的条件。但是(取决于您的环境),可能会为了速度而放弃断言。(在C语言中,您可以使用#ifdef,在Java中可以使用查找AOP,在Python中,
    assert
    中的任何内容都只能在传递--debug标志时运行,等等)如果您的断言中出现性能问题,它是可以解决的。然而,我倾向于让它们一直开着,直到你有理由不这样做

  • 您的一些逻辑将自然地从单元测试转移到post条件。但是,有必要确保您有单元测试,这些单元测试可以针对您的post条件运行所有感兴趣的案例。如果为了提高速度而放弃生产中的断言,这一点尤其正确

  • Post条件不是单元测试。用任何对他们的工作有意义的方式来写。(一般来说,它们应该有些简单。)

  • 一般来说,您可以按照#2中所述,通过传入一组可能违反post条件的感兴趣的输入来测试post条件,并检查它是否违反。如果要测试post条件本身的逻辑,