C语言 Assert和单元测试不兼容吗?

r7s23pms  于 2023-05-16  发布在  其他
关注(0)|答案(6)|浏览(105)

我对测试一些包含来自assert.h的assert宏的函数有一些担心。
如果Assert失败,则测试也失败。这给我留下了一些永远不会工作的测试用例。
例如,一个函数不是指示失败(返回false或类似的东西),而是Assert。
是否有解决方案(包含assert的单元测试函数)?

avwztpqn

avwztpqn1#

也许只有我这么认为,但我认为如果你有Assert失败,你甚至不应该考虑更高级别的单元测试,直到你把它们修复。这个想法是Assert应该永远在任何情况下失败,包括单元测试,如果代码编写正确。至少我是这样写代码的。

oymdgrw7

oymdgrw72#

您可以测试Assert在您期望的时候中止(在错误的输入时)。
测试框架Google Test作为一个ASSERT_DEATH宏,它将测试程序在您期望的地方中止(如Assert)。
您也可以使用定义的NDEBUG(-DNDEBUG with gcc)进行编译,以禁用单元测试的Assert。

gfttwv5a

gfttwv5a3#

不,单元测试是你在开发过程中所做的。Assert是运行时构造。
根据我的经验,大多数情况下,Assert在生产中是关闭的。但你应该总是测试。
CppUnit是一个很好的测试框架。它是C++的nUnit家族的一部分。

omvjsjqw

omvjsjqw4#

Assert在任何情况下都不应该失败。如果它们在测试中失败,则表明存在逻辑错误。基本上,如果你的函数正在执行“assert(0)”而不是返回错误代码,那么这个函数应该重写。如果中止是期望的行为,那么exit()是合适的,而不是assert()。
如果Assert在测试期间失败,则代码出错,必须更改。代码“assert(x)”应该被解释为“程序的逻辑要求x为真。如果你有一个导致Assert失败的单元测试,那么这个语句显然是无效的,必须修改。

bihw5rsg

bihw5rsg5#

这听起来就像你的测试框架不是为了测试你的Assert而构建的。
使用一个将停止进程的Assert,您需要一些东西来监视您的执行状态。
boost-test如何执行此操作的示例:http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/prg_exec_monitor/index.html
我已经有一段时间没有写C或C++代码了,但是,我会从类似的技术开始。

fbcarpbf

fbcarpbf6#

假设你的代码准备好了优雅地处理那些Assert被关闭时会触发Assert的情况,并且你想对这些情况进行单元测试,确保这些情况确实被优雅地处理,一种方法是编译一个测试可执行文件,在相关的对象文件中禁用Assert。
例如,假设你在Foo.c中有这个函数:

Foo* bar(int const i)
{
    assert(i != 0);
    if (i == 0)
    {
        /*
         * When asserts are disabled, this returns `NULL`.
         * 
         * The code below can safely assume that `i != 0` --
         * not just because there's an assert up there, but
         * because this early return gracefully handles the
         * case where `i` is 0 when asserts are disabled.
         */
        return NULL;
    }
    
    // Do something with `i` here and return a non-`NULL` pointer.
}

您想测试当用0调用时,bar()是否实际返回NULL
在makefile中,假设你有两个可执行文件:

  1. ${MAIN_EXE},你编写应用程序的常规可执行文件,以及你希望启用Foo.c的Assert**的地方
  2. ${TESTS_EXE},运行单元测试的可执行文件,您希望Foo.c的Assert被禁用
    Foo.c,您还可以生成 * 两个不同的对象文件 *:
  3. Foo.o,assertsenabled的那个,要链接到${MAIN_EXE}
  4. Foo_test.o,assertsdisabled的,要链接到${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

现在,当运行测试可执行文件时,只会启用测试可执行文件的Assert,允许您像这样对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的Assert仍将正常启用,提醒您代码中的错误。

相关问题