Reputation: 10820
I have some concerns related to the fact of testing some functions containing the assert macro from assert.h.
If the assert fails the test fails also. This leaves me with some test cases that will never work.
For example a function instead of indicating failure (return false or something similar) asserts.
Is there a solution for this (unit-testing functions containing assert)?
Upvotes: 8
Views: 10322
Reputation: 111
Assuming your code is prepared to gracefully handle cases that would trigger asserts when those asserts are turned off, and you want to unit test that those cases are indeed handled gracefully, a way to do this is to compile a test executable with assertions disabled in the relevant object files.
For example, say you have this function in 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.
}
You want to test whether bar()
actually returns NULL
when called with 0
.
In your makefile, say you have two executables:
${MAIN_EXE}
, your regular executable where you're writing your app and where you want Foo.c
's asserts enabled${TESTS_EXE}
, the executable that runs your unit tests and where you want Foo.c
's asserts disabledFrom Foo.c
, you can also generate two different object files:
Foo.o
, the one with asserts enabled, to be linked into ${MAIN_EXE}
Foo_test.o
, the one with asserts disabled, to be linked into ${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
Now, when running your test executable, only the test executable's asserts will be enabled, allowing you to unit test bar()
like this:
Foo* f = NULL;
f = bar(0); // Won't trigger the assert in `Foo.c`!
assert(f == NULL);
f = bar(5);
assert(f != NULL);
When running your regular executable, Foo.c
's asserts will still be enabled as normal, alerting you to errors in your code.
Upvotes: 0
Reputation: 212168
Assertions should never fail under any circumstance. If they fail in your tests, it indicates a logical error. Basically, if your function is doing "assert( 0 )" instead of returning an error code, then the function should be re-written. If aborting is the desired behavior, then exit() is appropriate, but not assert().
If an assertion ever fails during your tests, then the code is in error and must be changed. The code "assert( x )" should be interpreted to mean "The logic of the program requires that x be true. Under no circumstance can it be false." If you have a unit test that causes an assertion to fail, then the statement is clearly invalid and must be modified.
Upvotes: 4
Reputation: 399
You could be testing the fact that that assert aborts when you expect it to (on bad input).
The test framework Google Test as an ASSERT_DEATH macro that will test that the program aborts where you expect it to (like an assert).
You could also compile with NDEBUG defined ( -DNDEBUG with gcc) to disable assertions for your unit tests.
Upvotes: 13
Reputation: 1814
It basically sounds like your test framework wasn't built to test your assertions.
With an assert that will halt the process, you need something that will monitor your execution state.
Example of how boost-test does this: http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/prg_exec_monitor/index.html
I've not done C or C++ coding in some time, but, I'd start with a similar technique.
Upvotes: 1
Reputation: 131550
Maybe it's just me, but I would think that if you have assertion failures, you shouldn't even be thinking about higher-level unit testing until you get them fixed. The idea is that assertions should never fail under any circumstances, including unit tests, if the code is written properly. Or at least that's how I write my code.
Upvotes: 14
Reputation: 308733
No, unit testing is what you do during development. Asserts are a run-time construct.
In my experience, most of the time asserts are turned off in production. But you should always be testing.
CppUnit is a fine test framework. It's part of the nUnit family for C++.
Upvotes: 7