CodeItNow

MockItNow

MockItNow is a C++ mocking framework I started in 2007 to improve my productivity when writing unit tests. I’ve been using it for nearly a year now in my projects at home, so I thought it was about time I shared it. It’s a little rough around the edges, but it provides some really nice features that I haven’t seen in other C++ mocking frameworks.

Currently the only compiler/CPU architecture supported is Microsoft/x86, however I’ve seen it working under gcc and PowerPC, so it can be done! In order to stay clear of any legal issues, I can’t make those versions available at the moment.

If you’re interested in the Microsoft/x86 version, then you can download it for free here. You are free to use MockItNow for any application, but a thank you credit would be nice if you find it useful.

If you’re interested in contributing a new version to the project, then please email me.

Considerations

Apparently there’s no such thing as a free lunch, so there are some things you will need to consider when setting up your projects to be mockable. For most of these, you won’t have to worry about them once you’ve gotten them right. A couple of them require a tiny bit of extra code to be written for each new type you want to record, but the I’ve found that this cost is small compared to the gains from using MockItNow.

Function Interception

MockItNow works by intercepting function calls and redirecting them in order to record and replay. It does this via a special flag that Microsoft added to their compiler in order to support profiling. This means that you have to be a little careful with your project settings to make sure that you don’t optimize out those function calls.

In particular, you need to disable:

  • Inlining
  • Incremental linking
  • COMDAT folding

If these settings aren’t disabled then you’ll see the mocker failing to mock certain functions, or incorrectly mocking other functions. The need for compile setting changes also means that you’re not going to be able to mock functions from code you haven’t compiled yourself (like third party compiled libraries).

Also, you need to make sure that the classes you use with the mocker have default constructors. This is to ensure that they can be returned during the record phase, and that virtual functions can be fixed up.

Performance

There is a performance hit you take when enabling mocking, since you now need to do two function calls for every one you had before. In practice I haven’t had any problems so far with performance, however, you should be aware that this could be an issue. The good news is that there are ways around this problem. For example, you don’t pay the performance hit (but can’t mock functions) if you don’t specify the /Gh flag for the compiler. This means that you could have different configurations depending on whether you want mocking (and hence the unit tests) enabled or not.

Argument Comparison

MockItNow needs to be able to compare function call arguments. It defaults to doing this by using operator==. This means that if you write a class and want to be able to stub a function which takes that class as a parameter, then you need to supply an operator== for that class type.

You can actually customize the comparer for specific types to use other methods (compare memory, compare by address), but I wouldn’t recommend it.

Error Reporting

MockItNow reports errors by throwing standard library exceptions. The first thing you need to do is to make sure that exceptions are enabled in your project settings. Beyond this, you need to make sure that whatever unit testing framework you use (I use UnitTest++) catches std::exception in all cases. I believe that the latest version of UnitTest++ already does this.

In order to show friendly error messages to the user, MockItNow uses ostream to print out the expected and actual arguments. This means that for new types that you want to use as recorded function parameters, you need to supply an implementation of operator<< for ostream.

Usage

Once you have addressed the considerations above, you should be ready to start using MockItNow. Using the mocker is basically broken down into three steps: Register, record and replay. Although you can use the Mocker class directly as the MockItNow unit tests do, I’ve provided some macros to help out with doing most of the common tasks. All you need to do is to inlcude MockItNow.h in your test file, create a Mocker class in your fixture, and you’re ready to go!

Register

The first thing you need to do is to register functions that you want to be able to record and replay. The reason for this step is to allow the compiler to generate replacement functions for the original which will do the actual recording and replaying of function arguments and return values. The following are some examples of using the register macro:

REGISTER(FreeFunction);
REGISTER(Foo::MemberFunction);
REGISTER(Foo::StaticFunction);

That’s all you need to do for most cases! If the function is overloaded, then you need to help the compiler out and tell it which overload you want to register by providing the function signature:

REGISTER_OVERLOADED(Foo::OverloadedMemberFunction, bool (Foo::*)(int, float));

Once a function is registered then it is allowed to be replayed, but there is no expectation that it will be called, so if you try to replay it without recording it first, then you will call the original function.

I found that sometimes this behavior is not what I want. In particular, I want some functions to always return a specific value whether they were recorded or not. For this reason I added another macro to tell the mocker to always stub out a particular function. If the function has a return value, then you must provide the value you want to use at register time:

REGISTER_STUB(Foo::FunctionThatReturnsVoid);
REGISTER_STUB(Foo::FunctionThatReturnsInt, 12345);

As soon as you put the mocker into replay mode during the test, the above functions will never be called, and instead the replacement functions will run, and any supplied return values will be returned. Note that using this macro does not set up an expectation inside the mocker, so if you don’t call these functions then it won’t complain.

Record

Once you have registered your functions, the next step is to set up some expectations. These are basically an ordered list of function calls you expect to see called when the code under test is run. For functions with a return value, you must supply that return value to the mocker at record time using a macro. For functions that return void, you can just place the function call inside the record block, or optionally use a macro.

The following example puts the mocker into record mode, sets some expectations, and finally puts the mocker into replay mode (this happens implicitly when the record scope is exited).

Foo foo;


RECORD
{
foo.FunctionThatReturnsVoid();
EXPECT_RETURN(foo.FunctionThatReturnsInt, 54321);
EXPECT(foo.FunctionThatReturnsVoid);
}

During the record phase, you can tag on some functions to the end of the EXPECT macros which instruct the mocker to change its behavior during the replay of that function:

  1. Ignore(X): This tells the mocker to ignore differences about specific aspects of the function during replay. These can be particular arguments (Argument1, Argument2 etc.), all arguments (AllArguments), or the object a member function is being called on (This).

CallOriginal(): This calls the original function. You’ll probably only need this if you’re trying to do something with recursive functions.

  1. FailWhenCalled(): This tells the mocker to expect that the function won’t be called, and to fail if it does get called.
  2. ReturnArgument(X, Y): You can use this to return values into arguments passed in as non-const references.

These can be chained together however you like:

Foo foo;
int result;


RECORD
{
EXPECT(Foo::FunctionWithOutParameter(result, 2, 3, 4)).Ignore(Argument1).ReturnArgument(Argument1, 123);
}

Sometimes you may want to always return a certain value from a particular function. You can use the RETURN_ALWAYS macro to do this. Unlike the other expectations, the order of this function call in the RECORD block doesn’t matter.

Replay

There’s nothing more to be done when you have finished recording other than to run your test code. During this phase, the mocker looks for functions to replay using the following rules:

  1. Is there an explicit expectation set using EXPECT or EXPECT_RETURN, and does the object (if it is a member function) match?
  2. Is there a RETURN_ALWAYS expectation set, and does the object (if it is a member function) match?
  3. Was the function registered using REGISTER_STUB?

If all three conditions fail, then the function is not replayed.

When the mocker is destroyed, it runs through the list of expected function calls, verifies that they were called, and that all of the arguments matched the recorded arguments.

Examples

I have provided a project illustrating how to use MockItNow on Google Code, you can het it here.

This file includes the Examples project, the latest version of MockItNow, and UnitTest++. The projects are provided in Visual Studio 2005 format, and should compile out of the box.

Please note that this is a slightly modified version of UnitTest++, since the current release doesn’t catch std::exception in all cases. If you already use UnitTest++, you may just want to look at the diffs to see where I needed to add catch blocks.

I’ve provided three configurations for the Examples project: Debug, Release and Final. Debug and Release configurations both run the unit tests, but Final has optimizations turned on, and so does not run the tests.

If you’re just interested in seeing what the the test code looks like when using MockItNow, you can browse the example file.

9 Comments so far

  1. Tim June 26th, 2008 6:40 am

    Hey,
    Just wanted to say thanks for this! It’s a fantastic tool. Really appreciate you putting the time in.

    For others trying to use this, the only thing that bit me was that the example project defaults to the Final configuration which has optimizations turned on. The result is that most of the tests will fail with that config. This is noted on the post dedicated to the example project but not here so I was clueless for a while. Hope that helps someone.

    Cheers!
    -Tim

  2. rory June 26th, 2008 11:14 am

    Thanks for the feedback Tim! It’s nice to know that someone else out there is finding MockItNow useful. I look back at the time when I was having to inherit from class in order to stub its functions and shudder!

    I don’t think that I am able change the default build configuration for the solution, since I think that’s stored in the per-user settings.

    Still, I’ve added the information from my post to the bottom of this page which should help.

    Apologies for the confusion!

    Rory

  3. cheol September 11th, 2008 11:02 pm

    Hi,

    Great stuff! Thanks for releasing this.

    I have trouble to use it in Linux environment. Have you a success it with Linux and g++?

    Thanks

    cheol

  4. rory September 12th, 2008 8:54 am

    Hi,

    I’ve never actually used it in Linux before, but I have seen it working using gcc on the ps3, where we used the following flags when compiling:

    -Wall -Werror -fexceptions -finstrument-functions -mbase-toc

    The instrument functions flag tells the compiler to insert the hooks. To intercept the function calls, you’d just have to replace the current thunk file with something like this:

    namespace MockItNow
    {
    int g_jumpAddress;

    extern “C” void __cyg_profile_func_enter(void*, void *) __attribute__((no_instrument_function));

    void __cyg_profile_func_enter(void* callingFunctionAddress, void*)
    {
    // Same implementation as before
    }

    extern “C” void __cyg_profile_func_exit(void*, void*) __attribute__((no_instrument_function));

    void __cyg_profile_func_exit (void*, void*)
    {
    }
    }

    This is all just off the top of my head, so take it with a grain of salt. One thing in particular I’m not sure about is the location in the prologue of the jump to the profiling function. It is inserted at the very top of the prologue by the MS compiler, and if gcc does the same then it should just work. Otherwise you might need to change the prologue in the thunk to account for this.

    I don’t have a linux box I’m afraid, so I can’t actually test all this out. If you get it working, then let me know and I’ll add you as a contributor to the project.

    Rory

  5. LESchwartz November 7th, 2008 10:31 am

    The example program runs great. However, we use CppUnit here. MockItNow seems to rely on UnitTest++ functionality, and I have been unsuccessful at getting it working in with CppUnit. Any suggestions would be helpful.

    Larry

  6. rory November 7th, 2008 11:55 am

    Hi,

    I haven’t tried it with other unit testing frameworks, but the only changes I made to UT++ were to add catch blocks for std::exception. What kind problems are you seeing? If you have the test app set up with CppUnit, you can mail it to me (rory) at this domain, and I can take a look at it.

    Rory

  7. lance November 13th, 2008 8:09 am

    Hey, looks like this could be very useful, thanks.

    I’ve been looking, but I can’t yet see a way to mock ‘out’-reference parameters. i.e. void getMultipleRefs( A &a, B& b, C&c);
    where the values of a,b,c are something i want to have during my test method, but getMultipleRefs is pulling their values in from other systems - so I want to mock the method, and set the value of the refs. Of course, I could just refactor the method to return a class containing the values I want - but I will have to get buy-in on TDD first!
    Any thoughts?

    Cheers,

    Lance

  8. lance November 13th, 2008 8:38 am

    Actually, it seems I’m an idiot, or can’t decipher camelcasing - just saw NoReturnWithOutArgument while looking at another problem :)

  9. rory November 13th, 2008 10:58 am

    Haha. That’s ok. I just replied on google code. But yeah, that’s how you do it, using ReturnArgument.

Leave a reply