我经常遇到这样一个问题,即模拟对象需要在某个状态之前被带到某个状态。测试的一部分可以开始。
例如,我想说我想测试以下类:
struct ToTest
{
virtual void onEnable();
virtual void doAction();
};
因此,我创建了以下模拟类:
struct Mock : ToTest
{
MOCK_METHOD0(onEnable, void());
MOCK_METHOD0(doAction, void());
};
第一个测试是在启用使用onEnable
对象的系统时调用ToTest
:
TEST(SomeTest, OnEnable)
{
Mock mock;
// register mock somehow
// interesting part of the test
EXPECT_CALL(mock, onEnable());
EnableSystem();
}
到目前为止,这么好。第二个测试是当系统执行操作并启用时调用doAction
。因此,应该在测试的有趣部分开始之前启用系统:
TEST(SomeTest, DoActionWhenEnabled)
{
Mock mock;
// register mock somehow
// initialize system
EnableSystem();
// interesting part of the test
EXPECT_CALL(mock, doAction());
DoSomeAction();
}
这有效,但是对onEnable
无趣的召唤发出了恼人的警告。这个问题似乎有两个常见的解决方法:
NiceMock<Mock>
来抑制所有此类警告;和EXPECT_CALL(mock, onEnable())
声明。我不想使用第一种方法,因为可能还有其他无趣的调用确实不应该发生。我也不喜欢第二种方法,因为我已经测试过(在第一次测试中)在启用系统时调用onEnable
;因此,我不想在所有适用于已启用系统的测试中重复这种期望。
我希望能够做的是说所有模拟调用都应该被完全忽略。在这个例子中,我希望只从测试的有趣部分开始检查期望&#34;评价。
有没有办法使用Google Mock实现这一目标?
答案 0 :(得分:3)
令人讨厌的是,必要的函数在那里:gmock/gmock-spec-builders.h
定义Mock::AllowUninterestingCalls
和其他来控制特定模拟对象的警告的生成。使用这些功能,应该可以暂时禁用有关不感兴趣的呼叫的警告。
Mock
有一些可以被滥用的模板朋友(例如,NiceMock
)。所以我创建了以下解决方法:
namespace testing
{
// HACK: NiceMock<> is a friend of Mock so we specialize it here to a type that
// is never used to be able to temporarily make a mock nice. If this feature
// would just be supported, we wouldn't need this hack...
template<>
struct NiceMock<void>
{
static void allow(const void* mock)
{
Mock::AllowUninterestingCalls(mock);
}
static void warn(const void* mock)
{
Mock::WarnUninterestingCalls(mock);
}
static void fail(const void* mock)
{
Mock::FailUninterestingCalls(mock);
}
};
typedef NiceMock<void> UninterestingCalls;
}
这允许我通过UninterestingCalls
typedef。
答案 1 :(得分:0)
根据设计,gmock无法实现您所寻求的灵活性。来自gmock Cookbook(强调我的):
[...]你应该非常谨慎地使用唠叨或严格的嘲讽,因为它们往往会使测试变得更脆弱,更难维护。当您重构代码而不改变其外部可见行为时,理想情况下您不需要更新任何测试。但是,如果您的代码与愚蠢的模拟进行交互,那么您可能会因为更改而开始收到警告。更糟糕的是,如果您的代码与严格模拟交互,您的测试可能会开始失败,您将被迫修复它们。 我们的一般建议是在大多数情况下使用漂亮的模拟(不是默认模式),在开发或调试测试时使用naggy mocks(当前默认模式),并且仅使用严格的模拟作为最后的手段。
不幸的是,这是我们和许多其他开发人员遇到的问题。 Jeff Langr在其着作Modern C++ Programming with Test-Driven Development中写道(第5章,关于测试双打):
测试设计怎么样?当我们从手动模拟解决方案改为使用Google Mock时,我们将一个测试分成两个。如果我们在单个测试中表达了所有内容,那么一个测试可以设定涵盖所有三个重要事件的期望。这是一个简单的解决方案,但我们最终会得到一个混乱的测试。
[...]
使用
NiceMock
,我们承担的风险很小。如果代码稍后以某种方式更改为在[...]接口上调用另一个方法,我们的测试就不会知道它了。您应该在需要时使用NiceMock
,而不是习惯性的。如果您经常需要它,请寻求修复您的设计。
答案 2 :(得分:-1)
您可能最好在第二次测试中使用不同的模拟类。
class MockOnAction : public ToTest {
// This is a non-mocked function that does nothing
virtual void onEnable() {}
// Mocked function
MOCK_METHOD0(doAction, void());
}
为了使此测试起作用,您可以让onEnable不执行任何操作(如上所示)。或者它可以做一些特殊的事情,比如调用基类或做其他逻辑。
virtual void onEnable() {
// You could call the base class version of this function
ToTest::onEnable();
// or hardcode some other logic
// isEnabled = true;
}