Baz
Baz

Reputation: 13135

Unit Testing when using Input Iterators

Lets pretend that the class C below is very slow and that I don't want it in my unit tests. So I create a MockC which will eventually implement the same interface as the C class.

class IC
{
public:
    virtual std::string getName() = 0;
};

class C: public IC
{
public:
    C(){}
    C(int c) : _c(c){}
    int _c;
    virtual std::string getName()
    {
        // do really slow stuff with an external library
        ...
    }
};

class MockC: public IC
{
public:
    MockC(){}
    MockC(int c) : _c(c){}
    int _c;
    virtual std::string getName()
    {
       ...
    }
};

I also have a stripped down input iterator which creates an object of type Value (could be C or MockC) when dereferenced:

template<class Value>
class GetNextIterator 
{
public:
    typedef int (*GetNext)();

    GetNextIterator(GetNext getNext): _getNext(getNext)
    {
        _current = _getNext();
    }

    const Value* operator->() const
    {
        return new Value(_current);
    }

protected:
    int _current;
    GetNext _getNext;
};

int count = 0;
int getNext()
{
    return count++;
}

And then I have another class which is also very slow which is a parent to C class objects but which also has its own properties, as follows:

class ID
{
public:
    virtual std::string getName() = 0;
};

class D: public ID
{
public:
    typedef GetNextIterator<C> Iterator;

    virtual ChildIterator begin() const
    {
        return Iterator(getNext);
    }

    virtual std::string getName()
    {
        // again really slow and accessing external dependencies
        ...
    }
};

Now how do I go about testing the following function, just as an example:

int f(D* d)
{
    D::ChildIterator i = d->begin();
    if (d.getName() == "something or other")  
        return i->_c;
    else
        return 1;
}

Remember, I don't wish to use the concrete classes C or D. What should I do to fully unit test f() and similar functions? I'm totally open to redesigning any of the code above to make this work with unit tests.

Upvotes: 0

Views: 324

Answers (1)

Chris O
Chris O

Reputation: 5037

Only mock what you need to mock. For the purposes of testing f()'s behavior, you're on the right track with mocking out the heavy C object. You do have to write enough test cases to cover whatever behavior you think f() will need to handle. But you don't need to mock the Container itself, that should be easily testable. So, get rid of the IContainer concept.

However, you do need to modify Container such that it accepts inputs of IC objects instead of concrete objects (also you don't need this to be template based, if just for testing, Container could hold literal IC*). Both the test code and production code will supply a real Container object to f(). The test code will first fill up a Container with the MockC objects, whereas the production code will fill up a Container with C objects, before calling f().

Upvotes: 1

Related Questions