How To Mock C Functions with Isolator++

600px-Capital_CDo you know the TIOBE survey? Every month it shows the usage of programming languages world wide. And coming in in first place this month is… C!

That’s right. There’s so much development still being done in C, where performance and program size matters, and the object orientation of C++ is a hindrance. Plus, we’re talking about so many new devices that C is their native language (apart from assembler).

With so many programs written in C, there’s obviously a need for unit testing. And where unit testing goes, mocking follows.

So here’s a reminder, how you can simply mock global C methods with Isolator++.

Here’s the code-under-test. It’s a method called SafeDelete, and it looks for a file before deleting it, using the global functions fopen, fclose and remove:

void SafeDelete(const char* filename)
{
	FILE* fp = fopen(filename, "r");
	if (fp == NULL)
	{
		throw ("File does not exist");
	}
	else
	{
		fclose(fp);
		remove (filename);
	}
}

As we all know, messing with files in a unit test is a no-no. The test takes a long time to finish, and we also need to take care of setup and clean up of files. So we want to mock the C calls. Here’s the first test, where we check that if the file is not there, we expect an exception to be thrown:

TEST_F(FileHandlerTests, SafeDelete_NoFile_ExceptionThrown)
{
	FAKE_GLOBAL(fopen);
	WHEN_CALLED(fopen(_,_)).ReturnPtr(NULL);

	FileHandler* handler = new FileHandler();  bool result = false;

	try
	{
		handler->SafeDelete("AnyFile");
	}
	catch (char* exception)
	{
		if (strcmp(exception, "File does not exist") ==0)
			result = true;
	}

	delete (handler);
	ASSERT_TRUE(result);
}

With the FAKE_GLOBAL macro, we tell Isolator++ to mock fopen. Then in the next line, we tell fopen to return NULL when it gets called. When it does, the exception gets thrown, and we can check the contained message.


For the next test, we’re going to check what happens when the file is there. If a file exists, fopen need to return a non-NULL value. Then, we need to mock also the calls for fclose and remove, so we won’t have any nasty side effects or unforeseen exceptions.

TEST_F(FileHandlerTests, SafeDelete_ThereIsFile_RemoveWasCalled)
{
	FAKE_GLOBAL(fopen);
	FAKE_GLOBAL(fclose);
	FAKE_GLOBAL(remove);

	FileHandler* handler = new FileHandler();
	handler->SafeDelete("AnyFile");
	delete(handler);

	ASSERT_WAS_CALLED(remove(_));
}

Two things to point. The

 SafeDelete

method does not return a value, so our pass/fail criteria is that

 remove

was actually called

.

In this example, I’m using the

 ASSERT_WAS_CALLED

macro with

 _ macro

as an argument to specify I don’t care about the arguments at runtime. Second, you’ll note that in this test I’m not setting any behavior on

 fopen. fopen

returns a pointer, and Isolator++ returns automatically an allocated pointer.This is enough to satisfy the

if-NULL

check.Couldn’t get any simpler, can it? So the next time you bump into a C function that hampers your tests, Isolator++ can get you out of that jam. If you’d like to know more about mocking in C and C++ we’re running a webinar on the topic. Register now!


			

						
						
TOP