断言和单元测试不兼容吗?

问题描述 投票:0回答:6

我对测试一些包含来自 assert.h.

的断言宏的函数有一些担忧

如果断言失败,测试也会失败。 这给我留下了一些永远无法工作的测试用例。

例如一个函数而不是指示失败(返回 false 或类似的东西)断言。

是否有解决方案(包含断言的单元测试函数)?

c++ c unit-testing assertions
6个回答
13
投票

也许这只是我,但我认为如果你有断言失败,在你修复它们之前你甚至不应该考虑更高级别的单元测试。这个想法是,如果代码编写得当,断言在任何情况下都应该 never 失败,包括单元测试。或者至少我是这样写代码的。


13
投票

您可能正在测试断言在您期望的时候(输入错误)中止的事实。

测试框架 Google Test 作为 ASSERT_DEATH 宏,它将测试程序是否在您期望的位置中止(如断言)。

您还可以使用定义的 NDEBUG 进行编译(-DNDEBUG 与 gcc)以禁用单元测试的断言。


7
投票

不,单元测试是你在开发过程中所做的。断言是一个运行时构造。

根据我的经验,大多数时候断言在生产中被关闭。但是您应该始终进行测试。

CppUnit 是一个很好的测试框架。它是 C++ 的 nUnit 系列的一部分。


3
投票

断言在任何情况下都不应失败。如果它们在您的测试中失败,则表明存在逻辑错误。基本上,如果您的函数执行“assert(0)”而不是返回错误代码,那么应该重写该函数。如果中止是所需的行为,则 exit() 是合适的,但 assert() 不合适。

如果断言在测试期间失败,则代码有误,必须更改。代码“assert( x )”应该被解释为“程序的逻辑要求 x 为真。在任何情况下它都不能为假。”如果你有一个导致断言失败的单元测试,那么这个语句显然是无效的,必须修改。


1
投票

基本上听起来您的测试框架不是为了测试您的断言而构建的。

有了一个会停止进程的断言,你需要一些东西来监视你的执行状态。

boost-test 如何做到这一点的例子: http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/prg_exec_monitor/index.html

我有一段时间没有完成 C 或 C++ 编码,但是,我会从类似的技术开始。


0
投票

假设您的代码已准备好妥善处理断言关闭时会触发断言的情况,并且您想对这些情况进行单元测试确实处理得当,一种方法是编译带有断言的测试可执行文件在相关目标文件中禁用。

例如,假设你在

Foo.c
中有这个功能:

Foo* bar(int const i)
{
    assert(i != 0);
    if (i == 0)
    {
        /*
         * NOTE: The code below does NOT assume that `i != 0`
         * just because there's an assert up there.
         * 
         * When asserts are disabled, this returns `NULL`.
         */
        return NULL;
    }
    
    // Do something with `i` here and return a non-`NULL` pointer.
}

你想测试

bar()
在用
NULL
调用时是否真的返回
0

在您的 makefile 中,假设您有两个可执行文件:

  1. ${MAIN_EXE}
    ,您的常规可执行文件,您正在编写您的应用程序以及您want
    Foo.c
    的断言enabled
  2. ${TESTS_EXE}
    ,运行单元测试的可执行文件以及您想要
    Foo.c
    的断言disabled

Foo.c
,您还可以生成两个不同的目标文件

  1. Foo.o
    ,带有断言 enabled 的那个,将链接到
    ${MAIN_EXE}
  2. Foo_test.o
    ,带有断言disabled的那个,被链接到
    ${TESTS_EXE}
# Main executable recipes
${MAIN_EXE}: main.o Foo.o
    ${CC} ${CFLAGS} main.o Foo.o -o ${MAIN_EXE}

Foo.o: Foo.c Foo.h
    ${CC} ${CFLAGS} -c Foo.c -o Foo.o

# ...

# Unit test executable recipes
${TESTS_EXE}: tests.o Foo_test.o
    ${CC} ${CFLAGS} tests.o Foo_test.o -o ${TESTS_EXE}

# For the test object, disable `Foo.c`'s asserts with `-DNDEBUG`.
Foo_test.o: Foo.c Foo.h
    ${CC} ${CFLAGS} -DNDEBUG -c Foo.c -o Foo_test.o

现在,当运行您的测试可执行文件时,只有测试可执行文件的断言将被启用,允许您像这样进行单元测试

bar()

Foo* f = NULL;

f = bar(0); // Won't trigger the assert in `Foo.c`!

assert(f == NULL);

f = bar(5);

assert(f != NULL);

运行常规可执行文件时,

Foo.c
的断言仍将正常启用,提醒您代码中的错误。

© www.soinside.com 2019 - 2024. All rights reserved.