it-swarm.cn

断言或单元测试更重要吗?

断言测试和单元测试都充当代码库的文档,并且是发现错误的一种手段。主要区别在于,断言充当健全性检查并查看实际输入,而单元测试则在特定的模拟输入上运行,并且是针对单个明确定义的“正确答案”的测试。使用断言与单元测试作为验证正确性的主要方法有哪些相对优点?您认为应该重点强调哪个?

52
dsimcha

Asserts有助于您了解程序的内部状态。例如,您的数据结构具有有效状态,例如Time数据结构将不包含_25:61:61_的值。断言检查的条件是:

  • 确保呼叫者遵守合同的前提条件,

  • 后置条件,确保被叫方遵守合同,以及

  • 不变量,可确保函数返回后数据结构始终具有某些属性。不变式是先决条件和后置条件的条件。

单元测试有助于您了解模块的外部行为。在调用Push()方法后,您的Stack可能具有一致的状态,但是如果在调用3次之后堆栈的大小没有增加3,则这是一个错误。 (例如,在不正确的Push()实现仅检查断言和退出的情况下。)

严格来说,断言和单元测试之间的主要区别在于单元测试具有测试数据(使程序运行的值),而断言则没有。也就是说,您可以自动执行单元测试,而不能对断言说相同。为了便于讨论,我假设您正在谈论在高阶功能测试(该程序执行整个程序,而不像单元测试那样驱动模块)的上下文中执行程序。如果您不打算将自动化功能测试作为“查看实际输入”的手段,那么很显然,价值在于自动化,因此单元测试将获得成功。如果您在(自动)功能测试的上下文中谈论此问题,请参见下文。

被测试的内容可能会有一些重叠。例如,Stack的后置条件实际上可能断言堆栈大小增加了1。但是在该断言中可以执行的操作有一定的局限性:是否还应该检查top元素是刚刚添加的元素?

两者的目标都是提高质量。对于单元测试,目标是发现错误。对于断言,目标是通过观察无效的程序状态,使它们更容易调试。

请注意,都不技术验证正确性。实际上,如果您进行单元测试的目的是验证程序是否正确,则很可能会提出无用的测试,您知道该方法会起作用。这是一种心理效应:您将尽一切努力实现自己的目标。如果您的目标是发现错误,那么您的活动将反映出来。

两者都很重要,并且都有自己的目的。

[关于断言的最后说明:要获得最大价值,您需要在程序的所有关键点上使用它们,而不是几个关键功能。否则,问题的原始来源可能已经被掩盖,并且如果不进行数小时的调试就很难发现。]

43
Macneil

在谈论断言时,请记住,只需轻按一下即可将其关闭。

一个非常糟糕的断言示例:

_char *c = malloc(1024);
assert(c != NULL);
_

为什么这样不好?因为如果由于定义了NDEBUG之类而跳过了该断言,则不会执行任何错误检查。

单元测试(可能)只是对上面的代码进行段错误。当然,它是通过告诉您出了点问题来完成工作的,还是这样做了? malloc()在测试中失败的可能性有多大?

当程序员需要暗示没有“正常”事件会导致断言触发时,断言用于调试目的。 malloc()确实是正常事件,因此不应断言。

在许多其他情况下,使用断言而不是充分处理可能出错的事情。这就是为什么断言获得不良声誉的原因,以及诸如Go之类的语言不包含断言的原因。

单元测试旨在告诉您您所做的更改何时破坏了其他内容。它们的目的是在您每次执行程序时,使您(在大多数情况下)免于遍历程序的每个功能(但是,测试人员对于发布很重要)构建。

两者之间确实没有任何明显的相关性,只是两者都告诉您出了点问题。可以将断言视为您正在处理的事情的断点,而不必使用调试器。可以将单元测试视为告诉您是否破坏了您正在工作的东西的东西。

7
Tim Post

它们都是用于帮助提高所构建系统的整体质量的工具。在很大程度上取决于您使用的语言,所构建的应用程序的类型以及您在哪里花费的时间最多。更不用说您对此有一些看法。

首先,如果您使用的语言没有assert关键字,则不能使用断言(至少不能使用我们在此所说的方式)。长期以来,Java没有assert关键字,并且仍然没有许多语言。因此,单元测试变得更加重要。在某些语言中断言仅在设置了标志时运行(再次Java这里)。)当保护不总是存在时,这不是一个非常有用的功能。

有一种流派说,如果您“断言”某件事,则不妨编写一个if/_throw有意义的异常块。这种思考过程来自于放置在方法开头的许多断言,以确保所有值都在边界之内。测试您的前提条件是拥有预期后置条件的非常重要的部分。

单元测试是必须编写和维护的额外代码。对许多人来说这是一个缺点。但是,使用当前的大量单元测试框架,您可以用较少的代码生成大量的测试条件。参数化测试和“理论”将对大量数据样本执行相同的测试,这些数据样本可能会发现一些难以发现的错误。

我个人发现单元测试比散布断言要多,但这是因为我大部分时间都在开发平台(Java/C#)。其他语言具有更强大的断言支持,甚至“按合同设计”(见下文)也提供了更多的保证。如果我使用这些语言之一,那么我可能会比单元测试更多地使用DBC。

http://zh.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support

5
Berin Loritsch