eranpeer / FakeIt

C++ mocking made easy. A simple yet very expressive, headers only library for c++ mocking.
MIT License
1.24k stars 170 forks source link

Mocking a class with multiple inheritance #112

Closed alonbar closed 6 years ago

alonbar commented 6 years ago

Hi everyone, I'm new to FakeIt and would like to integrate it into my unittests. I know that multiple inheritance is a known limitation, but it's also a pretty serious limitation. I was wondering whether there are any workarounds you know of that I can use in order to mock a class with multiple inheritance.

thanks

eranpeer commented 6 years ago

Yes, it is a limitation. Fakeit is built to handle simple pure abstract classes. Hacking the virtual table of classes with multiple inheritance was too complicated for my to handle. I will be more than happy if someone out there will suggest a pull request with such an improvement. As for now, this stays a limitation. You can always create a simple interface (pure virtual) class that can be mocked and create an adapter from that class to the more complicated classes you may have. In most cases this will be regarded as a more elegant OO design as it encourages stronger decoupling.

AlexKven commented 5 years ago

I had this problem as well, and I figured out a workaround that you can use as long as your class can be instantiated (so no interfaces). You can make an instance of a class that uses multiple inheritance (e.g., class MyClass : public Base1, public Base2...), and create mocks around that instance that are of types Mock<Base1>, Mock<Base2>, etc. You can find a longer example on this question on Stack Overflow.

blurpy commented 3 years ago

I have a class using multiple inheritance like this:

class RandomAccessMemory: public ClockListener, public RegisterListener {
...
}

The listeners are just interfaces, with virtual methods.

I was initially met with static_assert: Can't mock a type with multiple inheritance when trying to mock this class. Then I tried to disable the assert, and mocking that class worked perfectly.

My commit can be seen here: https://github.com/blurpy/8-bit-computer-emulator/commit/3e1342fdd2dfb7baaf5564d99b74e27a8be56816

Seems like the check could be less strict?

Using gcc version 10.2.1 if it's important.

blurpy commented 3 years ago

Have now also tested cross platform.

The error on Windows are:

D:\a\8-bit-computer-emulator\8-bit-computer-emulator\test\include\fakeit.hpp(5317,28): error C2440: 'reinterpret_cast': cannot convert from 'R (__cdecl fakeit::VTUtils::getVTSize::Derrived::* )(void)' to 'unsigned int (__cdecl fakeit::VirtualOffsetSelector::* )(int)' [D:\a\8-bit-computer-emulator\8-bit-computer-emulator\build\test\8bit-tests.vcxproj]
D:\a\8-bit-computer-emulator\8-bit-computer-emulator\test\include\fakeit.hpp(5316,68): error C3536: 'sMethod': cannot be used before it is initialized [D:\a\8-bit-computer-emulator\8-bit-computer-emulator\build\test\8bit-tests.vcxproj]
D:\a\8-bit-computer-emulator\8-bit-computer-emulator\test\include\fakeit.hpp(5316,68): error C2297: '.*': illegal, right operand has type 'int' [D:\a\8-bit-computer-emulator\8-bit-computer-emulator\build\test\8bit-tests.vcxproj]

I added ifdefs around the affected test to avoid failures when building on Windows.

unitron92 commented 1 year ago

I have the same problem !