Reputation: 5029
I have a library that provides class Foo
. I extend Foo
with some of my own member functions in class FooExtended
. In order to use FooExtended
in my unit tests I must make it mockable, therefore I create an interface IFoo
and this is the type I use all throughout my codebase. Then I created two implementations of the interface:
Class FooMock
- used for unit tests.
Class FooWrapper
- used in the actual program. Mainly it's a wrapper for FooExtended
, an instance of which it stores as a member.
Problem: The problem is with the FooWrapper
. I don't know how to utilise the factory Lib::create_foo()
to create Foo
as the library wants, but also have the my_added_function()
which I added in FooExtended
. The dynamic_cast
fails.
#include <iostream>
#include <memory>
#include <cassert>
using namespace std;
// What's in this namespace is in a 3rd party lib that I cannot change.
namespace Lib {
class Foo {
public:
virtual ~Foo() {};
int lib_func() {
return 42;
}
};
// Factory
Foo* create_foo() {
return new Foo();
}
} // namespace Lib
/** I want to extend the 3rd party class, and only use
this extended class in my project */
class FooExtended : public Lib::Foo {
public:
float my_added_func() {
return 1.0;
}
};
/** Interface for class Foo, created so that a mock
implementation of `FooExtended` can be created for unit tests. */
class IFoo {
public:
virtual int lib_func() = 0;
virtual float my_added_func() = 0;
};
/** Mock implemenation of IFoo for unit-tests. */
class FooMock : public IFoo() {
// Blah blah
}
/** Non-mock implementation of IFoo. Just a wrapper for the class with the
actual implementation, i.e. FooExtended. */
class FooWrapper : public IFoo {
public:
int lib_func() override {
assert(mFooExt); // This fails because dynamic_cast failed.
return mFooExt->lib_func();
};
float my_added_func() override {
assert(mFooExt); // This fails because dynamic_cast fails.
return mFooExt->my_added_func();
}
private:
unique_ptr<FooExtended> mFooExt {
unique_ptr<FooExtended>(
// This dynamic_cast fails.
dynamic_cast<FooExtended*>(Lib::create_foo()))
};
};
int main() {
unique_ptr<IFoo> foo { unique_ptr<IFoo>(new FooWrapper()) };
assert(foo != nullptr);
cout << "Starting...";
// Exits the program because of the assert inside.
cout << foo->lib_func() << "\n";
cout << foo->my_added_func();
}
Upvotes: 0
Views: 118
Reputation: 19043
If you are not afraid to pay the price for calling virtual functions, you can create a wrapper for Foo and use it in your program:
class IFoo {
public:
virtual ~Foo() {};
virtual int lib_func() = 0;
};
class MyFoo : public IFoo {
int lib_func() override { _foo.lib_func(); }
private:
std::unique_ptr<Foo> _foo = create_foo(); // pseudocode
};
Now you can create mock and use it for IFoo.
Upvotes: 1