是否可以同时依赖 gMock 中的预期调用?
Is it possible to depend expected calls in gMock together?
假设我想测试以下功能:
template<typename Pack>
bool is_valid(const Pack& pack) {
if (pack.a() > 0)
return pack.b();
return false;
};
我会为Pack
写一个小mocker如下:
class PackMock {
public:
MOCK_METHOD(int, a, (), (const));
MOCK_METHOD(bool, b, (), (const));
};
现在我尝试在测试函数中编写测试此方法:
TEST(MyTests, IsValidTest) {
PackMock p;
EXPECT_CALL(p, a())
.WillOnce(Return(0))
.WillOnce(Return(1))
.WillOnce(Return(20));
EXPECT_CALL(p, b())
.WillOnce(Return(true))
.WillOnce(Return(false))
.WillOnce(Return(true));
EXPECT_FALSE(is_valid(p));
EXPECT_FALSE(is_valid(p));
EXPECT_TRUE(is_valid(p));
}
乍一看,这段代码应该没问题。我有 3 个期望和我的嘲笑者 returns 3 个不同的值集,这就是实际应用程序 运行ning(数据方面)中发生的情况。
但是如果你运行这段代码,你会得到一个错误,提示不满足模拟者的期望(它说b()
被调用两次时预计会调用3次)。原因是当第一次测试发生时,a()
returns 0
,并且由于 if
条件,根本没有调用 b()
。所以最后,一切都搞砸了。
现在我想知道是否有办法将这些期望联系在一起,或者我应该始终根据代码的工作方式而不是我的数据的工作方式来设置我的期望?我个人认为后者应该是正确的。例如,如果在 mocker 中调用 a()
,我们确保我们总是满足 b()
中的 1 个期望?或者例如,我们将这些期望链接在一起,仅当 a() > 0
?
时才期望 b()
首先,您可以使用 testing::Sequence
实例按顺序跟踪模拟调用。您也可以直接为测试定义 InSequence
,如 docs.
其次,您的第一个 EXPECT_CALL
不会调用 b()
模拟调用,因为 a()
returns 0
然后永远不会评估 return pack.b()
.
作为 here 中的示例,我已经说明了如何在您的示例中使用 Sequence
class,如下所示:
TEST(MyTests, IsValidTest) {
// Setup the mock object
PackMock p;
// Keep track of the sequence of events
// using a sequence class
testing::Sequence sequence;
// # First is_valid() - a
EXPECT_CALL(p, a())
.InSequence(sequence)
.WillOnce(Return(0));
// # First is_valid() - b - not called
// EXPECT_CALL(p, b())
// .InSequence(sequence)
// .WillOnce(Return(true));
// # Second is_valid() - a
EXPECT_CALL(p, a())
.InSequence(sequence)
.WillOnce(Return(1));
// # Second is_valid() - b
EXPECT_CALL(p, b())
.InSequence(sequence)
.WillOnce(Return(false));
// # Third is_valid() - a
EXPECT_CALL(p, a())
.InSequence(sequence)
.WillOnce(Return(20));
// # Third is_valid() - b
EXPECT_CALL(p, b())
.InSequence(sequence)
.WillOnce(Return(true));
// Act - Initiate the calls and inject the
// mock object as a dependency
// # First call - a() returns 0,
// thus returns false (but() b is not called)
EXPECT_FALSE(is_valid(p));
// # Second call - a() returns 1,
// thus returns false, because b returns false
EXPECT_FALSE(is_valid(p));
// # Third call - a() returns 20,
// thus returns true, because b returns true
EXPECT_TRUE(is_valid(p));
}
这将提供以下输出:
Running main() from /opt/compiler-explorer/libs/googletest/release-1.10.0/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from MyTests
[ RUN ] MyTests.IsValidTest
[ OK ] MyTests.IsValidTest (0 ms)
[----------] 1 test from MyTests (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
因此,回答你的问题:
Is it possible to depend expected calls in gMock together?
是,使用 testing::Sequence
class 或仅使用 testing::InSequence()
因此,如果您在测试中有相互依赖的调用,请使用序列 class 个实例到 link 它们。
假设我想测试以下功能:
template<typename Pack>
bool is_valid(const Pack& pack) {
if (pack.a() > 0)
return pack.b();
return false;
};
我会为Pack
写一个小mocker如下:
class PackMock {
public:
MOCK_METHOD(int, a, (), (const));
MOCK_METHOD(bool, b, (), (const));
};
现在我尝试在测试函数中编写测试此方法:
TEST(MyTests, IsValidTest) {
PackMock p;
EXPECT_CALL(p, a())
.WillOnce(Return(0))
.WillOnce(Return(1))
.WillOnce(Return(20));
EXPECT_CALL(p, b())
.WillOnce(Return(true))
.WillOnce(Return(false))
.WillOnce(Return(true));
EXPECT_FALSE(is_valid(p));
EXPECT_FALSE(is_valid(p));
EXPECT_TRUE(is_valid(p));
}
乍一看,这段代码应该没问题。我有 3 个期望和我的嘲笑者 returns 3 个不同的值集,这就是实际应用程序 运行ning(数据方面)中发生的情况。
但是如果你运行这段代码,你会得到一个错误,提示不满足模拟者的期望(它说b()
被调用两次时预计会调用3次)。原因是当第一次测试发生时,a()
returns 0
,并且由于 if
条件,根本没有调用 b()
。所以最后,一切都搞砸了。
现在我想知道是否有办法将这些期望联系在一起,或者我应该始终根据代码的工作方式而不是我的数据的工作方式来设置我的期望?我个人认为后者应该是正确的。例如,如果在 mocker 中调用 a()
,我们确保我们总是满足 b()
中的 1 个期望?或者例如,我们将这些期望链接在一起,仅当 a() > 0
?
b()
首先,您可以使用 testing::Sequence
实例按顺序跟踪模拟调用。您也可以直接为测试定义 InSequence
,如 docs.
其次,您的第一个 EXPECT_CALL
不会调用 b()
模拟调用,因为 a()
returns 0
然后永远不会评估 return pack.b()
.
作为 here 中的示例,我已经说明了如何在您的示例中使用 Sequence
class,如下所示:
TEST(MyTests, IsValidTest) {
// Setup the mock object
PackMock p;
// Keep track of the sequence of events
// using a sequence class
testing::Sequence sequence;
// # First is_valid() - a
EXPECT_CALL(p, a())
.InSequence(sequence)
.WillOnce(Return(0));
// # First is_valid() - b - not called
// EXPECT_CALL(p, b())
// .InSequence(sequence)
// .WillOnce(Return(true));
// # Second is_valid() - a
EXPECT_CALL(p, a())
.InSequence(sequence)
.WillOnce(Return(1));
// # Second is_valid() - b
EXPECT_CALL(p, b())
.InSequence(sequence)
.WillOnce(Return(false));
// # Third is_valid() - a
EXPECT_CALL(p, a())
.InSequence(sequence)
.WillOnce(Return(20));
// # Third is_valid() - b
EXPECT_CALL(p, b())
.InSequence(sequence)
.WillOnce(Return(true));
// Act - Initiate the calls and inject the
// mock object as a dependency
// # First call - a() returns 0,
// thus returns false (but() b is not called)
EXPECT_FALSE(is_valid(p));
// # Second call - a() returns 1,
// thus returns false, because b returns false
EXPECT_FALSE(is_valid(p));
// # Third call - a() returns 20,
// thus returns true, because b returns true
EXPECT_TRUE(is_valid(p));
}
这将提供以下输出:
Running main() from /opt/compiler-explorer/libs/googletest/release-1.10.0/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from MyTests
[ RUN ] MyTests.IsValidTest
[ OK ] MyTests.IsValidTest (0 ms)
[----------] 1 test from MyTests (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
因此,回答你的问题:
Is it possible to depend expected calls in gMock together?
是,使用 testing::Sequence
class 或仅使用 testing::InSequence()
因此,如果您在测试中有相互依赖的调用,请使用序列 class 个实例到 link 它们。