7

I'm in the process of integrating a Unit Testing Framework for an existing code base in C++. I've zeroed down on CxxTest, but as it turns out we can use other Mocking Frameworks (like googlemock) in conjunction with CxxTest too.

After reading tutorials on CxxTest (Mocking) and googlemock (the infamous turtle example), I have the general idea that you have to define a mock class (using macros etc), declare an object of the mock class and then pass it to the function you are unit testing. Now, there are many occurences in the existing code base where it isn't possible to do that.

Here's an pseudo example to clarify:

class CCandidateForTest
{
    public:
    bool foo(int a)
    {
        CAnotherClass obj;
        int b = obj.bar(a+2);
        if (a == b) {
            return true;
        } else {
            return false;
        }
    }
}

(This is over-simplified, there are also exceptions and the primitive types may also be other objects etc.; but you get the general idea) (also, creation of objects is not always direct and may sometimes use a factory)

I want to write a test for the function CCandidateForTest::foo. This method internally creates an object of CAnotherClass, which I need to mock so that CAnotherClass::bar returns different values so that different code paths in foo are traversed in unit testing.

In a nutshell, the problem is that the function being tested internally creates an object of the class that needs to be mocked - hence passing an instance of the mocked object to the function is not possible.

How do I use mocking in such a case? Is there a specific mocking framework that makes this possible?

4 Answers 4

3

You could use a factory to create instances of CAnotherClass.

class CCandidateForTest
{
    public:
    bool foo(int a)
    {
        std::shared_ptr< CAnotherClassInterface > obj = CAnotherClassFactory::Create();
        int b = obj->bar(a+2);
        if (a == b) {
            return true;
        } else {
            return false;
        }
    }
}

CAnotherClassFactory can look like :

class CAnotherClassFactory
{
public:
    typedef std::shared_ptr< CAnotherClassInterface > (*fn)();
    static std::shared_ptr< CAnotherClassInterface > Create()
    {
        return createFn();
    }

    static fn createFn;
};

Random thoughts about your approach :

  • If that is over-simplified, then you need to think how to refactor it.
  • there are better unit test frameworks then cxxunit. gtest and cute-test.com
8
  • Most of the times the object creation is already using a factory. Do you think this could be leveraged by making sure the factory returns a mock instead of an actual in case of a unit test environment. I'm looking at pre-processor "flags" and #ifdefs in the factory method while compiling for test. Isn't this a too custom-made approach? Writing #ifdefs in just the factories seems much better than mingling with actual code (like dependency injection); but that would make the overall design too specific, wouldn't it?
    – dotbugfix
    Jan 16, 2014 at 10:40
  • @dotbugfix You can do that with macros as well. I am not sure what you mean with "that would make the overall design too specific". Every design is specific for certain set of requirements. With the use of dependency injection, you break the coupling in a very nice way - and that is good. Jan 16, 2014 at 12:21
  • 1
    Why is shared_ptr required here?
    – James
    Jan 16, 2014 at 13:45
  • @James I assumed that CAnotherClassInterface (interface of CAnotherClass class) is an abstract class, and I assumed that the created object is destroyed at the end of the foo function. Jan 16, 2014 at 14:02
  • 1
    unique_ptr does that too
    – James
    Jan 16, 2014 at 14:08
4

If a class internally creates objects to do its job, then that object isn't a "collaborator" at all. For testing purposes, this is exactly the same situation as if it had a lot of inline code doing the same thing. In other words, you can't mock this object because from the perspective that the test has to assume, it doesn't exist!

(This may be an indicator of your class doing too much, and it can be an argument when weighing whether to refactor the class so that it does have a true collaborator, but it is only one factor - there may be other good reasons to leave the class unchanged and test its behaviour as well as possible without mocking.)

1
  • 1
    I see where you're getting at with "lot of inline code doing the same thing"; but the purpose here is to make the unit test more modular. Also, we have to mock at some point in the end, because the objective here is to test how this particular function reacts to the behavior of the object that it created. Inputs/outputs from the function can be tested without mocking, but we're focussing on exception handling and how neatly it cleans up after itself (and so forth for n other methods)
    – dotbugfix
    Jan 16, 2014 at 10:42
4

Use a factory. Have the candidate class take in the factory in the constructor. Mock the factory for your test. You can use a mock lib for that or simply use separate prod and test impls of an pure abstract factory class.

-2

I saw that we had function which internal generated/created its own object for manipulating. From my view, it's not truly testable code. Therefore, if we tried to make unit test for it, it may not reflect true value of TDD here. In addition, it can make your unit test code and mock objects more complex. In balance way, we should have some refactor code before doing any UT then. We can do some way to refactor implementation such as: pass more argument to make it more compliant with testable code, use factory pattern/global function to generate object..

Not the answer you're looking for? Browse other questions tagged or ask your own question.