GUnit
GUnit copied to clipboard
"Hi-Perf" (non-virtual) Dependency Injection
If we are using the "Hi-Perf" Google.Mock feature https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#mocking-nonvirtual-methods
Then how does this affect the ideal use of GUnit?
- [ ] Can we still use the automatic mock generation?
- [ ] Can we still use
GUnit.GMake
? (since we are using derived class template args, notstatic_cast<iface&>
) - [ ] Can we still use
Boost.DI
? (I know, a question for a different repo)
Or any other trade-offs from using non-virtual methods?
Thanks @paulreimer for the questions
-
[ ] Can we still use the automatic mock generation?
- Unfortunatelly not out of the box as automatic mock injection requres GMocks
- You could still use it if you provide some sort of traits for the mocks, though
template<class> struct Mock; template<> struct Mock<MockPacketStream> { MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); MOCK_CONST_METHOD0(NumberOfPackets, size_t()); };
And this automatic mocks injection when resolve a type T
return Mock<T>();
-
[ ] Can we still use
GUnit.GMake
? (since we are using derived class template args, notstatic_cast<iface&>
)
- Sort of, as described above
- [x] Can we still use
Boost.DI
? (I know, a question for a different repo)
-
Yes, no issues here
example::example(ConcretePacketStream &); // no problems here, wiring not even needed
With templates no issues too
template<class T = class Stream> example::example(T stream);
di::bind<class Stream>.to<ConcretePacketStream>()
One thing, which might be useful when using templates is to avoid writing macros, though. That can be done by defining an interface instead and using GMock, automatic mock injection and DI without loosing performance at all as it will be injected via templates.
struct IStreamJustForTesting {
virtual ~IStreamJustForTesting () = default;
virtual void AppendPacket(Packet* new_packet) = 0;
virtual const Packet* GetPacket(size_t packet_number) const =0;
virtual size_t NumberOfPackets() const = 0;
};
di::bind<class Stream>.to<GMock<IStreamJustForTesting>()
OK, sounds good. I'm still trying to understand the first "automatic mock injection" part. Actually my question was more about the "automatic mock generation" part (e.g. avoiding macros), looks like it is possible as in the final example. So, at least we can define the interface in C++ (even if the concrete class doesn't inherit it) and avoid the MOCK_*
macros (yay!).
Also just to check if I understand correctly, but in the final example then any mocks generated for IStreamJustForTesting
will have dynamic dispatch (and use static_cast
), but this only applies to the mocks and the production implementations do not need that interface? (and this is the price we pay -- at test time -- for avoiding the macros)
Right, Macros might be avoided with interfaces and GMock.
Yes, exactly. No cost in production but dynamic dispatch in testing.