Google Mock:为啥期望的部分排序比总排序更难满足?
Posted
技术标签:
【中文标题】Google Mock:为啥期望的部分排序比总排序更难满足?【英文标题】:Google Mock: why is a partial ordering of expectations harder to satisfy than a total ordering?Google Mock:为什么期望的部分排序比总排序更难满足? 【发布时间】:2014-10-02 12:02:00 【问题描述】:我主要在 GoogleMock 中使用有序期望,所以所有 EXPECT_CALL
s 都写在 testing::InSequence
对象的范围内。
现在我想放宽排序,所以我将期望分成 2 个序列。你会说测试应该通过,但没有——它失败了,抱怨未满足的先决条件。我该如何推理?
编辑:我的代码的简化版本:
//InSequence s; // uncomment this and it works
for (int i = 1; i <= 2; ++i)
//InSequence s; // uncomment this and it doesn't work
EXPECT_CALL(mock1, produceMessage(_))
.WillOnce(DoAll(SetArgReferee<0>(val1), Return(false)))
.WillOnce(DoAll(SetArgReferee<0>(val2), Return(false)))
.WillOnce(DoAll(SetArgReferee<0>(val2), Return(false)));
EXPECT_CALL(mock2, handleEvent(A<MyType>()));
EXPECT_CALL(mock2, handleMessage(NotNull()));
因此,如果 InSequence 嵌套在 for
循环内,与 InSequence 在外部的情况相比,我应该有一个偏序,这是一个宽松的要求。
我得到的错误:
Mock function called more times than expected - returning default value.
Function call: handleMessage(0xd7e708)
Returns: false
Expected: to be called once
Actual: called twice - over-saturated and active
然后,在测试结束时:
Actual function call count doesn't match EXPECT_CALL(mock2, handleMessage(NotNull()))...
Expected: to be called once
Actual: never called - unsatisfied and active
【问题讨论】:
你能写一些示例代码吗? 刚刚添加了代码。 补充说明:将.RetiresOnSaturation()
附加在第 3 号期望修复部分订单情况。但不是我的真实案例,它更复杂。
produceMessage 长什么样子?
【参考方案1】:
在 GoogleMock 学习曲线上取得更多进展后,我将尝试以一种足以提供帮助的通用方式回答我自己的问题。
让我们考虑以下完全有序期望的示例:
InSequence s;
EXPECT_CALL(mock1, methodA(_)); // expectation #1
EXPECT_CALL(mock2, methodX(_)); // expectation #2
EXPECT_CALL(mock1, methodA(_)); // expectation #3
EXPECT_CALL(mock2, methodY(_)); // expectation #4
现在,让我们将排序一分为二。
InSequence s;
EXPECT_CALL(mock1, methodA(_)); // expectation #1
EXPECT_CALL(mock2, methodX(_)); // expectation #2
InSequence s;
EXPECT_CALL(mock1, methodA(_)); // expectation #3
EXPECT_CALL(mock2, methodY(_)); // expectation #4
其目的是允许来自两个序列的期望“合并”,即期望 #1 作为 #2 的先决条件和 #3 作为 #4 的前提条件,但不超过此。
但是,以下调用序列将满足完全有序的期望,但不能满足“部分有序”的期望:
mock1.methodA(); // call #1
mock2.methodX(); // call #2
mock1.methodA(); // call #3
mock2.methodY(); // call #4
原因:完全有序的期望得到满足的原因很明显:示例只是按照编写的顺序满足它们。作为InSequence
,他们一满意就退休。
但是,“部分排序”场景不起作用,因为调用 #1 将满足期望 #3,然后调用 #2 将与期望 #2 匹配,因为它以期望 #1 作为前提条件而无法满足。 .尽管从技术上讲,期望 #1 和 #3 是相同的,但它们以相反的顺序得到满足,因为它们不属于相同的顺序,因此失败。
我感觉 Google Mock 对这种现象的记录不够充分。我仍在寻找更好的形式化。我怀疑这里使用的“部分顺序”概念有问题。
【讨论】:
你找到解决这个问题的方法了吗? 没有。不是通用的。我相信一个通用的解决方案需要某种形式的回溯,但我没有考虑更多。 谢谢。我能够解决这个问题的变体,因为我可以通过其中一个参数的值来区分任一块中的 methodA。然后让第一个块中的 methodA 匹配那个值,在第二个块中匹配除那个值之外的所有内容。显然这并不适用于所有地方,它恰好适合我的问题。【参考方案2】:查看您的问题和答案,我认为您的案例是 DAG(有向无环图)的典型示例,可以通过对 EXPECT_CALL 的 InSequence 子句(不是 ::testing:: 命名空间中的 InSeqeunce 类)来解决。请参阅 gmock Cookbook 说明 here。 您的答案中提供的示例测试可以通过这种方式解决:
Sequence s1, s2;
EXPECT_CALL(mock1, methodA(_)).InSequence(s1, s2);
EXPECT_CALL(mock2, methodX(_)).InSequence(s1);
EXPECT_CALL(mock2, methodY(_)).InSequence(s2);
上面的测试代码将确保methodA在methodX和methodY之前被调用。此外,它不关心 methodX 和 methodY 的调用顺序。
【讨论】:
以上是关于Google Mock:为啥期望的部分排序比总排序更难满足?的主要内容,如果未能解决你的问题,请参考以下文章