如果assert失败,测试也会失败。 这让我有一些永远不会起作用的测试用例。
例如,一个函数而不是指示失败(返回false或类似的内容)进行断言。
是否有解决方案(单元测试包含assert的函数)?
也许只有我这么认为,但如果你遇到了断言失败,你甚至不应该考虑进行更高级别的单元测试,直到你把它们修好为止。这意味着,如果代码编写正确,无论是在单元测试中还是其他情况下,断言都永远不应该失败。至少这是我编写代码的方式。
不,单元测试是在开发过程中进行的。Asserts是运行时构造。
据我的经验,大多数情况下,在生产环境中关闭了asserts。但你应该始终进行测试。
CppUnit是一个很好的测试框架。它是C++的nUnit家族的一部分。
在任何情况下,断言都不应该失败。如果在测试中它们失败了,那么就表示存在逻辑错误。基本上,如果你的函数执行的是"assert(0)"而不是返回错误代码,那么这个函数应该被重新编写。如果中止程序是期望的行为,那么使用exit()是合适的,但不要使用assert()。
如果在你的测试中有一个断言失败了,那么代码就存在错误,必须进行更改。代码"assert(x)"应该被解释为"程序的逻辑要求x为真。在任何情况下都不能为假。"如果你有一个单元测试导致断言失败,那么这个语句显然是无效的,必须进行修改。
abort()
,但绝对不要使用 exit()
。 - Tom这基本上听起来像是你的测试框架没有构建用于测试你的断言。
使用会停止进程的断言,你需要有一些东西来监视你的执行状态。
boost-test 的示例: http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/prg_exec_monitor/index.html
我已经有一段时间没有编写 C 或 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中,假设您有两个可执行文件:
${MAIN_EXE}
,您常规的可执行文件,在其中编写应用程序,并且您希望启用Foo.c
的断言${TESTS_EXE}
,运行单元测试的可执行文件,在其中禁用Foo.c
的断言从Foo.c
中,您还可以生成两个不同的目标文件:
Foo.o
,启用断言的目标文件,将链接到${MAIN_EXE}
Foo_test.o
,禁用断言的目标文件,将链接到${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
的断言仍将像往常一样启用,以警告您代码中的错误。
i != 0
,因为它位于一个返回语句下面,如果i
为0
,则返回NULL
。我的意思是,如果没有在i == 0
时早期返回,那么下面的代码将假定i != 0
只是因为有一个断言。这很糟糕,因为如果禁用断言,那个断言就永远不会被执行,而假设可能会突然变得错误。我已经重新表达了它,希望更清晰一些,从"The code below can safely assume that `i != 0` --"这一行开始。 - 6equj5