How can I test a function expecting objects of some concrete types if I don't want to create objects of those types?

Viewed 57

Given a pre-existing base class B, I had to implement a derived class like this

struct D : public B {
    bool pred(X const& x, Y const& y) const override;
};

where the X class is a complicated monster, and Y is just a wrapper to a range Xs, i.e. Y supports meaningful begin() and end().

Next I had to write some tests for this class, but going through creating some Xs and Ys to test pred against seemed to be very complicated, so I reasoned that all that pred needs to do with y is looping on its wrapped range of Xs, and all it needs to do on all of those Xs and on the input x is just calling .someMember() on them.

Then why not testing pred on some classes that pretend to be X and Y?

So I rushed and defined appropriate Xmock and Ymock classes in the testing TU, and then moved pred implementation into a template free function:

template<typename X, typename RangeX>
bool helper(X const& x, RangeX const& r) {
    // implementation
}

and rewrote the member function in terms of the one above:

bool D::pred(X const& x, Y const& y) const {
    return helper(x, y);
}

Except that soon I found that I had to move helper's definition to the header file otherwise the testing TU wouldn't see it.


This is to say that when the idea above came to my mind it looked promising: I make the function that I want to test a template, so that I can pass to it whatever I want, provided it satisfies some concept. But than I was stuck into language-specific difficulties.


So the question is, is the one I described above a valid strategy? Or, can it be made valid by using other methods to deal with templates (explicit instantiation...)? Or maybe I should simply give up to the idea that I have to create object of those concrete types X and Y to test pred?

1 Answers

Unfortunately I don't know of any perfect solution to this problem in C++. If the class X was already a polymorphic type and the X interfaces you use in your bool pred were overridable, then of course you could create a class MockX: public X and test your code against it. But I guess you cannot change that part of the library code.

Given that, your solution with templated helper

template<typename X, typename RangeX>
bool helper(X const& x, RangeX const& r) {
    // implementation
}

is the only workaround to implicitly test bool pred without creating real X instance. Unfortunately you need to pollute your header with this template definition.

If class X definition was in another library than class B definition (and from your question I guess it is not the case), you could also use testing trick from C language: link your test executable against mock implementation of that library (and include headers from mocked lib includes dir).

Related