Re: A simple unit test framework
Bo Persson wrote:
....
Ok, then. If you were to develop a log() function, how many test cases would
you need for a black box testing?
Ah - that's a design question.
What are your design objectives ?
I assume you want to log various information.
Design objectives are like:
a) Must be configutable for different levels (error, warning, debug etc)
b) Must not consume compute resources when the level is not being used
c) Must be able to optimize away logging levels not wanted in release code.
d) Must be as simple as possible to use.
e) Formatting of log message must be not part of the mainline code
f) Must avoid problems with missing end logs etc
g) Must handle the order of initialization issues and still collect the
logging information even though no output has been determined
h) Must handle race conditions of multiple threads writing logs
simultaneously
...............
first unit test for logging
..............
AT_DefineTest( Log, Log, "Basic Logging test" )
{
void Run()
{
// set up a preference manager
// usually set up once for all the application
// preferences.
Ptr< ATLOGTEST_PreferenceManager * > l_pm =
new ATLOGTEST_PreferenceManager;
// set up a logging manager
ATLOGTEST_LogManager l_lm;
{
// set up a place to write logging messages
ATLOGTEST_LogWriter l_lw( l_lm );
// create a loglevel preference
Preference< int >
l_loglevel( "loglevel", ~0, "/FooProgram", l_pm );
// start a logging section (compound statement)
AT_STARTLOG(
l_lm, l_loglevel, AT_LOGLEVEL_SEVERE, "Some Description"
)
at_log("Some Variables")
<< 55 << 123.456 << "Some String";
AT_ENDLOG
AT_STARTLOG(
l_lm, l_loglevel, AT_LOGLEVEL_SEVERE, "Some Description"
)
at_log("Some Variables")
<< 55 << 123.456 << "Some String";
AT_ENDLOG
}
}
};
AT_RegisterTest( Log, Log );
Now you can ask why did we use AT_STARTLOG...AT_ENDLOG macros.
The start of a logging block has to be a macro to begin with since it
must be an if statement because of requirements b amd c.
The data is stored in a temporary log session and at AT_ENDLOG it
destructs and pushes out the log all in one go - satisfying requirement h).
You need to set up a preference value for requiremnt a. Hence the
prefrence manager.
One of my prior implementations of a logging interface used an interface
like:
STARTLOG(...) { log( "blah" ) << blah; }
.... which also satisfied requirements b and c, however, a few too many
times, a n ending "}" went astray which caused all kinds of hard to find
bugs (which worked when debug logging was turned on and failed when
debug logging was turned off... very annoying. So the {...} was
replaced with START() log( "blah" ) << blah; END which never caused any
problems whatsoever. It was about 5 years ago now so I don't remember
the exact details. We got to the point of writing a little lex script
to run thorugh the code looking for possible problems.
This is a somewhat simplistic account of the issues but the point is
that the test case was written first. The rest of the code is far more
complex.
I'm not sure if there were any more tests written for the logging
interface but it was used throughout the application so it was tested
quite alot as part of other tests.