Best Method For Writing Unit Tests

Started by
12 comments, last by Ectara 11 years, 2 months ago
Since variadic macros aren't standard C++98, I can't figure out how I would present an interface that is similar to what I had, without having four different versions of each assertion based on the number of parameters.

Perhaps treat the function itself as an argument to the macro (a la std::stream operators)?


void (*truth)(char const *file, int line, bool value);
void (*hope)(char const *file, int line, char const *mantra, bool imaginary = false);
void (*chastity)(char const *file, int line);
 
#define AssertNone(func) (func)(__FILE__, __LINE__)
#define AssertOne(func, value) (func)(__FILE__, __LINE__, value)
#define AssertExtra(func, value, extra) (func)(__FILE__, __LINE, value, extra)

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement

If you're only supporting certain compilers, you could just go ahead and use their versions of variadic macros ;)

This feels a bit dirty too, but you could do something like:


struct Asserter
{
	Asserter( const char* file, int line ) : file(file), line(line) {} const char* file; int line;
	void operator()(bool condition, const char* message=0, int dbgLevel=0)
	{
		if( !condition && dbgLevel != 42 )
		{
			printf( "Assertion failed - %s:%d - %s", file, line, message );
		}
	}
};
#define ASSERT Asserter(__FILE__, __LINE__)

void test()
{
	ASSERT( false, "MyMessage" );
}
Do you use exceptions for these assertions? I've never used them, and I'm trying to avoid ever using them in C++, despite their benefits.

No, I just use __debugbreak() / "asm int 3" if the debugger is attached, and/or set a global flag saying that the test has failed if in a unit test.

[quote name='swiftcoder' timestamp='1358821236' post='5024143']
Perhaps treat the function itself as an argument to the macro (a la std::stream operators)?
[/quote]
Yeah, I suppose I could do that. Though, if I pass the name of the assertion and have one variant for each number of parameters, I guess I could just as easily type a unique macro name based on the assertion type and parameter count. I guess my goal is to have a simpler interface that won't essentially require me performing the compiler's name mangling for it.

[quote name='Hodgman' timestamp='1358823111' post='5024151']
If you're only supporting certain compilers, you could just go ahead and use their versions of variadic macros ;)
[/quote]
Ack! I suppose that if I'm speaking English, I can use ASCII arrays for everything, too. :)

[quote name='Hodgman' timestamp='1358823111' post='5024151']
This feels a bit dirty too, but you could do something like:
[/quote]
Ooh. I forgot about operator(). This looks rather do-able. I can likely find a benefit of having an assertion be an instance of a class. Also, since this is dummied out if the debug level is zero, the performance of this isn't critical.

Now I'm running into the problem where the design is getting complicated. The assertion knows a little too much about the testing harness, and the testing harness knows a little too much about the assertion. I've had my hands dirty long enough to know that this amount of difficulty likely means a bad design.

Can't hurt to provide more information. The testing class keeps track of the number of assertions, and may keep more detailed information in the future. Every time an assertion that is part of a test evaluated, the testing class must be notified; this was achieved by having those assertions be member functions. Each assertion may have a different debug level, and it is allowed to be omitted. The assertion checks with the testing class to see what the debug level is, but that can be changed if necessary. A message is an optional parameter than can be omitted; I will eventually change the message data type from a pointer to const char to a const reference to a string class instance later, once I finish porting code over, so passing a null pointer for the message to indicate there is none isn't an option.

I'm not sure how I can solve this without reinventing the interface I already had.

This topic is closed to new replies.

Advertisement