eranpeer / FakeIt

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

Access underlying instance in `Do` lambda #217

Closed dmeehan1968 closed 2 years ago

dmeehan1968 commented 3 years ago

I had a requirement to add a stopwatch over a on/off method pair of an object, and decided to do that with a When(Method(class, method)).AlwaysDo(...) call.

However, I still needed to call the underlying instance implementation, but this doesn't appear to be accessible from within the Mock instance. e.g.

class foo {
public: 
  void bar() { }
};
Mock<foo> mock;
foo & instance = mock.get();  // <--this is a the mocked instance, not the underlying instance
When(Method(foo, bar)).AlwaysDo([&instance](){
  // do stopwatch code
  instance.get().bar(); // <-- this is recursive, calling the lambda until stack exhausted
});

The only way I could see to do it was to create my own underlying instance, and then pass that to the mock constructor:

foo _foo;
Mock<foo> mock(_foo);
When(Method(foo, bar)).AlwaysDo([&_foo](){
  // do stopwatch code
  _foo.bar(); // <-- this is NOT recursive
});

Another approach is to write a wrapper for the foo class, but that was more verbose in terms of code, and might be more prone to error for more complex classes.

It seems that spy's could really do with a getInstance() method to provide a reference to the underlying instance. I'm not c++ expert, there might be an alternative way of doing this.

FranckRJ commented 2 years ago

For traditional mocks it won't be possible because there isn't any "underlying instance" that was constructed. For spies I'm not sure if it's really that useful to have a function getInstance() because as you wrote you can just access the instance that you passed to the spy. I mean:

foo _foo;
Mock<foo> mock(_foo);
// Why do you need this:
mock.getInstance();
// When you can just do this:
_foo;

The reason why I'm reticent to add getInstance is because tradition mocks and spies share the same class, so if spies have getInstance then traditional mocks will have that function as well, but it won't be usable (and thus will require to throw an exception) because there isn't any underlying instance for them.

Do you really need a getInstance or do you think accessing _foo manually is enough ?

dmeehan1968 commented 2 years ago

Way to far in the past for me to remember the context of this, and as you point out, it would appear to be more sugar than necessity.

FranckRJ commented 2 years ago

Ok, I'll close this issue, if you ever need it again you can always reopen it (i guess) or at least create a new one.