这是我的测试情况。 googletest 中有一条注释,必须在调用模拟方法之前先设置 EXPECT_CALL (https://google.github.io/googletest/gmock_for_dummies.html#expectation-ordering)。我的问题是我有一个模拟对象,只会稍后初始化。在初始化之后,将立即调用模拟对象的模拟方法。 这样,因为我无法在尚不存在的模拟对象上设置 EXPECT_CALL。我被迫在创建模拟对象时及时设置 EXPECT_CALL 。现在我的测试中发生的情况是模拟方法调用首先发生在 EXPECT_CALL 之前。由于该序列,我的测试失败了,因为它没有捕获 EXPECT_CALL 中预期的模拟方法。 这是伪代码:
在代码中我正在测试。
Client client = new Client();
// some actions with client…
// Later on Document object is created…
std::unique<Document> doc = client->CreateDocument();
if (doc->Process())
{
….
在谷歌测试中。
TEST_F(ClientTesting, CanProcess)
{
… expect calls on client …
// Only being able to add expect call here because before this, document object is not yet created.
EXPECT_CALL(*mockDoc, Process).WillOnce(Return(true));
}
测试表明,在 Document 对象的 Process 方法上有一个无趣的模拟方法调用。那么它就会失败,说期望调用 Document 对象的 Process 方法,但没有调用。我相信这是因为模拟方法在单元测试中的 EXPECT_CALL 之前首先在被测代码中被调用。
我尝试在创建
sleep()
对象后添加一些 Document
,以查看对其进行的模拟方法调用是否会被 EXCEPT_CALL 捕获。
Client client = new Client();
// some actions with client…
// Later on Document object is created…
std::unique<Document> doc = client->CreateDocument();
sleep(2);
if (doc->Process())
{
….
最简单的解决方案:将
EXPECT_CALL
放入模拟的构造函数中:
https://godbolt.org/z/5YhfP9K6x
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace testing;
struct Doc
{
Doc()
{ EXPECT_CALL(*this, process).WillOnce(Return(true)); }
MOCK_METHOD(bool, process,());
};
auto f()
{
return std::make_unique<Doc>();
}
bool g()
{
return f()->process();
}
TEST(a,b)
{
EXPECT_TRUE(g());
}
或者为了获得更多控制,您可以将其包装在一个控制其返回值的类中: https://godbolt.org/z/5q8e6e846
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace testing;
struct IDoc
{
virtual bool process() = 0;
virtual ~IDoc() = default;
};
struct DocMock : IDoc
{
MOCK_METHOD(bool, process,(), (override));
};
struct DocWrap : IDoc
{
static inline bool retval = false;
bool process() override
{
EXPECT_CALL(mock, process).WillOnce(Return(retval));
return mock.process();
}
DocMock mock{};
};
std::unique_ptr<IDoc> f()
{
return std::make_unique<DocWrap>();
}
bool g()
{
return f()->process();
}
TEST(a,b)
{
DocWrap::retval=false;
EXPECT_FALSE(g());
}
如果通过静态变量处理它是一个好主意那就是另一个故事了。