13

I have two unit tests that share some state (unfortunately I can't change this since the point is to test the handling of this very state).

TEST(MySuite, test1)
{
    shared_ptr<MockObject> first(make_shared<MockObject>());
    SubscribeToFooCallsGlobal(first);
    EXPECT_CALL(*first, Foo(_));//.RetiresOnSaturation();
    TriggerFooCalls(); // will call Foo in all subscribed
}

TEST(MySuite, test2)
{
    shared_ptr<MockObject> second(make_shared<MockObject>());
    SubscribeToFooCallsGlobal(second);
    EXPECT_CALL(*second, Foo(_)).Times(1);
    TriggerFooCalls(); // will call Foo in all subscribed
}

If I run the tests separately, both are successful. If I run them in the order test1, test2, I will get the following error in test2:

mytest.cpp(42): error: Mock function called more times than expected - returning directly.
    Function call: Foo(0068F65C)
         Expected: to be called once
           Actual: called twice - over-saturated and active

The expectation that fails is the one in test1. The call does take place, but I would like to tell GoogleMock to not care after test1 is complete (in fact, I only want to check expectations in a test while the test is running).

I was under the impression that RetiresOnSaturation would do this, but with it I get:

Unexpected mock function call - returning directly.
    Function call: Foo(005AF65C)
Google Mock tried the following 1 expectation, but it didn't match:

mytest.cpp(42): EXPECT_CALL(first, Foo(_))...
         Expected: the expectation is active
           Actual: it is retired
         Expected: to be called once
           Actual: called once - saturated and retired

Which I have to admit, confuses me. What does it mean? How can I solve this?

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
  • ` SubscribeToFooCallsGlobal(first);` - you probably must unsubscribe it at the end of each TC. – PiotrNycz Oct 18 '15 at 17:58
  • @PiotrNycz Sure, but that's a workaround. Why does GoogleMock still check the call *after* the test ran? – Tamás Szelei Oct 19 '15 at 08:52
  • Because globals are globals. And as such (those globals) are pain in the a*s - and nobody and nothing (including gtest) can deal properly with globals – PiotrNycz Oct 19 '15 at 12:53
  • @PiotrNycz my point is: why doesn't GoogleMock clear the expectations after a test case ran? How can I make it clear them? To me it doesn't make sense to keep them in place after a test case finished running. – Tamás Szelei Oct 19 '15 at 12:55
  • Your mocks are still there (kept by your globals as `std::shared_ptr`) - so , how, according to you, gmock shall recognize they shall not participate in next test? My point is that they are subscribed - so they are called - but they expected to be called only once – PiotrNycz Oct 19 '15 at 13:15
  • I mean in first test you have one Mock subscribed. In 2nd test you have 2 mocks subscribed – PiotrNycz Oct 19 '15 at 13:16
  • Use RAII/ScopeGuard to subscribed/unsubscibe your mocks – PiotrNycz Oct 19 '15 at 13:17
  • " it doesn't make sense to keep them in place" - my point is that this is you, you are keeping them in place - not gtest/gmock – PiotrNycz Oct 19 '15 at 13:18
  • @PiotrNycz I'm not debating why it is happening (I'm aware) but rather why gmock works like this and asking if there is a way to make tests run independently. If you are saying that the only way to do that is by destructing the mock objects, then kindly add that as an answer with the relevant documentation parts (which I failed to find) and I'll accept it as a solution. – Tamás Szelei Oct 19 '15 at 14:35

1 Answers1

15

You can read in documentation of Mock almost literally described your case:

Forcing a Verification

When it's being destoyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate Google Test failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destoyed.

How could it be that your mock object won't eventually be destroyed? Well, it might be created on the heap and owned by the code you are testing. Suppose there's a bug in that code and it doesn't delete the mock object properly - you could end up with a passing test when there's actually a bug.

So you shall not expect, that at the end of the test case, in some magic way expectations will be "deactivated". As cited above - the mock destructor is the point of verification.

In your case - you mocks are not local variable - they are created in dynamic memory (heap in cited doc) and kept in your tested code via SubscribeToFooCallsGlobal(), So for sure mock created in one test is still alive in next test.

The easy, and proper solution is to unsubscribe at the end of each TC - I do not know if you have any UnsubscribeToFooCallsGlobal() - if not - create such function. To be sure that it will be always called - use ScopeGuard pattern.

There is one function to manually enforce verification Mock::VerifyAndClearExpectations(&mock_object) - but use it only if you need this verification not in the last line of your testcase, because that should be point of destruction.

edit: Fixed the googlemock link.

cscrimge
  • 385
  • 2
  • 9
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • You can also create Test Fixture class, and put this extra code to its TearDown method. This method is called after every test. You can also add SetUp method, which is called before every test. – Daniel Frużyński Aug 20 '20 at 11:07