Faking Global Methods

When writing C++ code, more often than not, C methods will find their way into your beautifully crafted C++ class. It happens when you need to compare a string, or open a file. And using the good old C functions makes your life easier, or plainly – you don’t have a choice. What would you do when you need to fake these C methods that do not belong to any class? That’s what FAKE_GLOBAL is for…

The problem at hand
Let’s pretend that in order to avoid calling these pesky C methods in multiple places in the code, I decided to write a simple wrapper around common file-related functionality. Our first order of business is to implement a method that deletes a file, and it needs to check if the file exist before attempting deletion. After a few minuets of work we have the following:

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

 



In order to test the method above, I need to go around three global C method calls: fopen, fclose and remove. On top of that we need to cause fopen to return a value – to simulate that it succeeded. Our pass/fail criterion is that remove was called. As you’ll see next, it’s easy to do all of the above using Isolator++.

Testing the code
Let's start by writing the test without fake objects:

TEST_F(FileHandlerTests, SafeDelete_FileExists_RemoveWasCalled)
{
    FileHandler handler;
 
    handler.SafeDelete("anyFile");
 
    ASSERT_WAS_CALLED(remove(0));
}

 

 



Notice At the bottom of the test we have a new macro – ASSERT_WAS_CALLED and you can guess from its name what it does. It checks are pass/fail criterion. Note that we don't bother with the argument –our test must fulfill the call with any argument in order to pass. This test will fail miserably because 'anyFile' does not exist and an exception will be thrown – it's time to fake some methods:

TEST_F(FileHandlerTests, SafeDelete_FileExists_RemoveWasCalled)
{
    FileHandler handler;
     FAKE_GLOBAL(fopen);
    FAKE_GLOBAL(fclose);
    FAKE_GLOBAL(remove);
     WHEN_CALLED(fopen(0,0)).Return((FILE*)1);
     handler.SafeDelete("anyFile");
     ASSERT_WAS_CALLED(remove(0));
}

 


 

Using FAKE_GLOBAL we’ve faked all calls to fopen, fclose and remove so they wouldn’t call our file system. But we need something more – we need to return a non-null value from fopen (simulate fopen succeeded). We’re using the WHEN_CALLED macro to tell Isolator++ what value to return from a specific function.

In this case we return a file handler/pointer that is not null – and will cause SafeDelete to believe that the file exists.

After adding these four lines the test will run and pass, but don’t take my word - try it for yourself.