[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: chef_wrap run issue, VS2010


What you are suggesting is pre-processor substitution. It should be avoided except when there is no other choice. It tends to sprinkle knowledge through the code that it is being tested. Linker time substitution is preferred, and I do not mean linker wrapping. I have a long example of linker substitution in my book.

Basically it works like this, compile all your production code into a library. Your test main and all test case files are explicitly compiled into the build, including any test-doubles, and finally you link with the library that contains your production code picking un any of the unresolved external references.

Link time substitution encourages you to partition code based on dependencies. It provides pressure to keep code modular and cohesive. Something like strdup, being in the runtime library can be linker substituted quite easily.

If you do want the preprocessor's help, or for special situations, you can use a command line define, rather than conditional compilation. That is better than sprinkling knowledge of testing into the production code. It is considered a test smell, letting the production code know (and change) while it is being tested.

That said, in CppUTest we use the preprocessor to override malloc and free for memory leak detection.

For example:
 on the command line use -Dmalloc=cpputest_malloc

In cpputest.c

	#undef malloc

	void * cpputest_malloc(size_t size)
	{
		void * men = malloc(size);
		//do some book keeping
		return men;
	}

We only use the preprocessor when there are not other good choices. I'd prefer to link time substitute it, but in this case it would not work, as we wanted the real malloc and we wanted to override it too. Linker wrapping is meant to solve the same problem.

A variation of preprocessor substitution is to do a forced include of a header file that has mappings from public name to test-double name like:

	#define malloc cpputest_malloc
	#define free cpputest_free


Then of course there are function pointers. If you need runtime substitution, then you may consider function pointers.

James
--------------------------------------------------------------------------
James Grenning - Author of TDD for Embedded C - wingman-sw.com/tddec
wingman-sw.com
wingman-sw.com/blog
twitter.com/jwgrenning
facebook.com/wingman.sw
[![wingman software](http://www.wingman-sw.com/images/wingman.png)](http://wingman-sw.com)
On 25 Feb 2016, at 2:55, Andreas Schneider wrote:

On Wednesday 24 February 2016 10:48:06 Daniel Miller wrote:
Right, the crashing itself isn't the real issue here; that was caused by me
mis-understanding how data was being passed around.  The core issue,
though, is that with VS, the wrapper function was not getting called, but the original chef_cook() was called instead; in other words, mocking was
not occurring.

Mocking can still be done with #define, but the --wrap feature of the linker
is much more elegant.

Example:

#ifdef UNIT_TESTING
char *mock_strdup(const char *p);

#define strdup mock_strdup

char *test_strdup(const char *p)
{
	static int count = 0;
	char *x;
	size_t len;

	count++;
	if (count % 10 == 0) {
		errno = EINVAL;
		return NULL;
	}

	x = calloc(1, len + 1);
	if (x == NULL) {
		return NULL;
	}
	memcpy(x, p, len);

	return x;
}

#endif


I think we need an example in the code for this.



--
Andreas Schneider                   GPG-ID: CC014E3D
www.cryptomilk.org                asn@xxxxxxxxxxxxxx