问题
The Google Mock documentation says:
Important note: Google Mock requires expectations to be set before the mock functions are called, otherwise the behavior is undefined. In particular, you mustn't interleave EXPECT_CALL()s and calls to the mock functions.
Does anyone know any details behind this restriction? I have a number of unit tests which definitely violate this rule but seem to function properly, however.
回答1:
I have to disagree with @Marko Popovic's assessment, and believe what he's done is undefined behavior that happens to work. I have personally seen what he is doing, interleaving calls, to appear to work just fine. But I think it's undefined behavior.
Nevertheless, I need clarity from Google, so I've opened this issue here: https://github.com/google/googletest/issues/2828. Please go upvote it to get it attention, as I'd like the Googletest team to clarify this themselves.
Update: Google has responded, and declared that @Marko Popovic's answer relies on undefined behavior. It is a very common trap to fall in, however, because, as Marko has pointed out, and as I have seen too, it does indeed work (most of the time at least). The problem is that it is relying on undefined behavior, and therefore may result in race conditions, be buggy, cause flaky tests, or otherwise not always work. Therefore, don't do it. Listen to Google. Their statement where they state the following is in fact correct:
In particular, you mustn't interleave
EXPECT_CALL()
s and calls to the mock functions (https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests)
Back to my original answer:
In this other answer of mine where I talk a lot about how to properly use multiple EXPECT_CALL()
s, I state interleaving is not okay: google mock - can I call EXPECT_CALL multiple times on same mock object?
[QUOTE FROM MY OWN WRITING START]
Question 3: Can I call EXPECT_CALL
to set some expectations on a mock method, call the mock method, then call EXPECT_CALL
on the method again to change the expectations, then call the mock method again?
This question wasn't even explicitly asked by the OP, but the only reason I found this page is because I was searching for this answer for many hours and couldn't find it. My Google search was "[gmock multiple expect_call][10]." Therefore, others asking this question will also fall on this page and need a conclusive answer.
A: NO, you can NOT do this! Although it may seem to work in testing, according to Google, it produces undefined behavior. See general rule #2 above!
"Important note: gMock requires expectations to be set before the mock functions are called, otherwise the behavior is undefined. In particular, you mustn't interleave
EXPECT_CALL()
s and calls to the mock functions" (https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests)
Therefore, this is NOT ALLOWED!
[QUOTE FROM MY OWN WRITING END]
Update (see the comments below my answer):
Perhaps this is NOT undefined behavior though!? All I added was Mock::VerifyAndClearExpectations(&myMockObj).
TEST(FooTest, testCaseName)
{
MyMock myMockObj;
...
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);
Mock::VerifyAndClearExpectations(&myMockObj); // <== NOTICE THIS ADDED LINE!
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
testMethod();
ASSERT_THAT(...);
}
References:
- @Marko Popovic's assessment
- Googletest issue where I ask for clarity about this: https://github.com/google/googletest/issues/2828
- [my own answer] google mock - can I call EXPECT_CALL multiple times on same mock object?
回答2:
Just as the documentation says, what is important is that expectations are set before the method is called. However, this does not mean
that it is not possible to interleave EXPECT_CALL
and invocation of mock method. It's just that you have to clear the expectations on the mock object yourself. For example, assume that we have the following mock
class
class MyMock : public bravo::IRealClass
{
public:
...
MOCK_METHOD1(myMethod, bool(int));
...
}
Now, assuming that a call to method testMethod
calls myMethod
once, you can write something like this in a test:
TEST(FooTest, testCaseName)
{
MyMock myMockObj;
...
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);
// Explicitly clear expectations and set new ones.
Mock::VerifyAndClearExpectations(&myMockObj);
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
testMethod();
ASSERT_THAT(...);
}
This will be fine since the mock object can be reliably reused again. However, if you omit to explicitly clear the expectations, you are entering the realm of undefined behavior. As is always the case with undefined behavior, it is possible that it won't crash and it might even work in some cases, but if you have have something like that in your code you should definitely fix it.
来源:https://stackoverflow.com/questions/40089204/interleaving-expect-calls-and-calls-to-the-mock-functions