7

I'm writing a unit-test to check some API calls. I am using check to test. My module is build with CMake (idk if it matters).

My test calls a function (which I need to test) and this function makes a call to another binary.

Simplified version of it looks like this.

/* unitTest.c */

#include "libraryAPI.h"
void letsMakeACall(void)
{
   ck_assert_eq(foo("water"), 0);
}

-- Module I am working on---
/*libraryAPI.c*/
#include "legacyLib.h"

void foo(const char *drink )    
{

    if (checkDrink(drink)!=0)
    {
       return 1;
    }else
    {
       return 0;
    }
}


----LEGACY BINARY---
/*legacyLib.c*/

static const char* expected = "water";

void checkDrink(const char *drink)
{
    if(drink == expected)
     {
        /*There are also a dozen functions being called which depend on legacy module initialisation*/
        return 0;
     }else{
        return 1;
     }
}

I'd like to mock response from legacyLib, because otherwise it call dozens of functions and breaks. My initial idea was to add some ifdef conditions when tests are being run, but it is against guidelines. Because it is basically a call interception I don't know what it a best(or working) solution. What can I use to solve it?

Oreols
  • 95
  • 6
  • If you want to test a function, it doesn't make sense to "mock" it. – Eugene Sh. Jul 30 '16 at 19:57
  • Yes, but I want to mock a response from one of the functions that are being called by the function I am trying to test. – Oreols Jul 30 '16 at 20:10
  • 2
    Where is that function defined? Can you replace the library implementing that function with a "mock" library? – Eugene Sh. Jul 30 '16 at 20:14
  • 1
    Having a mock library or DLL is a much cleaner way to do it than a bunch of ifdef's. – cdarke Jul 30 '16 at 22:31
  • I can replace the library, but in the end the test has to be run on a release candidate build. – Oreols Jul 31 '16 at 06:46
  • I asked a [similar question here](http://stackoverflow.com/q/38615983), there is a bounty, so if someone provides a good answer you might want to check there too in a couple of days. – Lou Jul 31 '16 at 12:16

1 Answers1

8

I am also unsure how to solve this generally, I have posted a similar question, but in some cases you can do the following (presuming you are testing individual functions):

  1. Include the .c file instead of the header .h, but after you "rename" your mocked function using a define directive:

    #define checkDrink checkDrink_mocked
    // preprocessor will now replace all occurrences of "checkDrink"
    // with "checkDrink_mocked"
    
    int checkDrink_mocked(const char *drink); 
    #include "legacyLib.c"
    #undef checkDrink
    
  2. Implement the renamed function:

    int checkDrink_mocked(const char *drink)
    {
        return 15;  
    }
    
Lou
  • 4,244
  • 3
  • 33
  • 72
  • 1
    Thanks. I think this is the best solution. In my case it was very simple getter-setter reference, so I just reimplemented it my module (less dependencies on stupid things :) ). – Oreols Aug 01 '16 at 08:37
  • 1
    Great, glad if it worked. This can easily fail if, for example, some `libraryAPI.c` function calls some extern function from a different module, which then calls back an original function from `libraryAPI.c` (`checkDrink` in this case), because linker will find the original function then. I have found a library called mimick ([Snaipe/Mimick](https://github.com/Snaipe/Mimick)) (author mentions it's still in alpha phase), which works by changing entries in the *"global offset table of the dynamic module at runtime"*, but I haven't tried it (it apparently supports GCC 4.6+, Clang 3.5+, MSVC 14+). – Lou Aug 01 '16 at 12:40