2

Imagine we have a unit test that first executes a sequence of code for which we expect a function someFunc not to be called, then executes a sequence of code for which we expect that function to be called exactly once. Using HippoMocks, we could write it like this:

#include <hippomocks.h>

void someFunc (void)
{

}

int main (int argc, char ** argv)
{
    MockRepository mocks;
    mocks.autoExpect = false;

    mocks.NeverCallFunc(someFunc); // line 27

    /* some testing code ... */

    /* ... in the course of which someFunc does not get called ... */

    mocks.ExpectCallFunc(someFunc); // line 33

    /* other testing code ... */
    someFunc();
    /* ... in the course of which someFunc got called */

    return 0;
}

However, when running the above snippet on Windows (compiled with Cygwin toolchain), a HippoMocks::ExpectationException is thrown:

terminate called after throwing an instance of 'HippoMocks::ExpectationException'
what():  Function someFunc() called with mismatching expectation!
Expectations set:
../main.cpp(33) Expectation for someFunc() on the mock at 0x0 was not satisfied.
Functions explicitly expected to not be called:
../main.cpp(27) Result set for someFunc() on the mock at 0x0 was used.

So I am wondering...

... (1), if HippoMocks is not designed to handle such a scenario. Does expecting that someFunc gets called (line 33) not replace the previous expectation in the corresponding mock respository?

... (2), why the second expectation (line 33) was not satified, as someFunc explicitely gets called. If any, I would have expected the first expectation (line 27) to not having been met?

Interestingly, things work the other way round. The following snippet runs without any issues:

#include <hippomocks.h>

void someFunc (void)
{

}

int main (int argc, char ** argv)
{
    MockRepository mocks;
    mocks.autoExpect = false;

    mocks.ExpectCallFunc(someFunc); // line 27

    /* some testing code ... */
    someFunc();
    /* ... in the course of which someFunc got called */

    mocks.NeverCallFunc(someFunc); // line 33

    /* other testing code ... */

    /* ... in the course of which someFunc does not get called ... */

    /* someFunc(); */ 

    return 0;
}

Moreover, if a call to someFunc is inserted behind the second expectation in the second snippet (as indicated in the comment), this is detected and reported as violation to the "never call" expectation by HippoMocks as one would expect:

terminate called after throwing an instance of 'HippoMocks::ExpectationException'
  what():  Function someFunc() called with mismatching expectation!
Expectations set:
../main.cpp(27) Expectation for someFunc() on the mock at 0x0 was satisfied.
Functions explicitly expected to not be called:
../main.cpp(33) Result set for someFunc() on the mock at 0x0 was used.

Any help of a HippoMocks expert would be appreciated...

FreakinGeek
  • 51
  • 1
  • 6

3 Answers3

3

Interaction between NeverCall and ExpectCall was not really thought through before - I never expected people to use NeverCall much at all, so I hadn't realized the interplay.

In the current released version a NeverCall would get an autoexpect on the previous ExpectCall, and all NeverCalls would be checked first. This results in ExpectCall/NeverCall to work as expected - ie, you first get the expect and then the NeverCall is active. In case of NeverCall/ExpectCall no autoexpects are added and the NeverCall gets priority. This is counter-intuitive and I think it's better to swap the behaviour so that ExpectCalls always get priority if they can match.

I've added your example as a new test case & swapped the match order of NeverCall and ExpectCall. I also removed the autoExpect for NeverCalls - because that shouldn't have been there in the first place. The result is that both of your examples will now work in the way you expect them to, autoExpect on or off. Your second example would also work if the someCall is after the NeverCall is set up. This allows you to group your setup code more than before.

If you want to test / switch to this version, note that it is still on the cpp11 branch. I will merge this to master & release when the branch is confirmed stable & the documentation properly expanded. There are no current known problems with it. It is on Github: https://github.com/dascandy/hippomocks/tree/cpp11 .

dascandy
  • 7,184
  • 1
  • 29
  • 50
1

You can't do that, because NeverCall is designed to throw an exception for the assertion. Seems completely illogical for me.

If you really want to get around that, setup the following

mocks.OnCallFunc(someFunc).Do(someFuncCalledHandler);

In your own handler you can implement the needed logic:

bool callAllowed = true; //global variable
void someFuncCalledHandler()
{
    if (!callAllowed)
    {
        throw MyNeverCallException();
    }
}

In your test, you can steer the behaviour of someFuncCalledHandler():

callAllowed = false;
someFunc();

By the way: It's a bad idea to mix up arrangement and action code in a test, as you've done in your sample code

mrAtari
  • 620
  • 5
  • 17
  • I agree that testing code and tested code should not be mixed up - this is for the sake of having a compact question only. – FreakinGeek Sep 22 '16 at 20:56
  • However, I do not agree that the usage of `NeverCall` and `ExpectCall` in interplay does not make sense: Besides emphasizing in the testing code the aspect that a given function must not be called during execution of a particular section of code - while being expected to be called during execution of another section -, explicitly stating this via `NeverCall` also leads to clearer messages in case the required constraint is not met - especially in case function parameters are involved. – FreakinGeek Sep 22 '16 at 21:14
  • Does the provided solution help you with your problem? – mrAtari Sep 22 '16 at 21:45
  • Well, it solves the problem for the compact example. But imagine we not only were expecting `someFunc` to be called in a particular section, but additionally would like to delegate work of `someFunc` to another function via `Do`, as is common in real world scenarios. Also, suppose we have more than one function with the original use case. I think things quickly might get confusing then with all the flags and manual never-call handlers. So I am still hoping for a solution which does not require manually reproducing the `NeverCallFunc` constraint functionality... – FreakinGeek Sep 23 '16 at 11:55
1

The Hippomocks expectations are checked either when the MockRepository's destructor is called or when its VerifyAll() method is explicitly called. Call VerifyAll() before line 33 and your first example shall work fine.

I second the previous answer that the testing code and the tested code shouldn't be mixed up but I can imagine that it's only for the sake of a compact question.

Roland Sarrazin
  • 1,203
  • 11
  • 29
  • Although it does not eliminate the need of inserting additional code into the test flow each time when facing the described scenario, manually calling `VerifyAll` seems to be a tolerable solution - at least it would avoid the need of adding one's own steering behavior implementation via `Do`... However, your suggested usage of `VerifyAll` does not work for me (tested with [latest version of Hippomocks](https://github.com/dascandy/hippomocks/tree/3b0d97bb7bd1a3916525f10d03430a57a0a3de8f/HippoMocks)). Still getting same output as described originally. Which version of Hippomocks are you using? – FreakinGeek Sep 22 '16 at 20:46
  • As for mixing testing code and tested code, you're completely right: my intention was to keep the example code as compact as possible. – FreakinGeek Sep 22 '16 at 20:55
  • I tested the original code and the modified code with `VerifyAll` with our version of hippomocks.h (version 4 if I recall correctly). Both (!) work fine. I tested both with the version you mentioned and both are throwing an exception. I'm afraid my answer doesn't answer your question but I'm sorry I don't have the opportunity to analyze the differences any further. – Roland Sarrazin Sep 26 '16 at 14:05