如何对在另一个模拟方法 C++ 中调用的模拟方法设置期望
How to set expectation on a mocked method which is called inside another mocked method C++
我是 google 测试框架的初学者,我已经在 SO 上查找了这个问题的解决方案,但找不到任何关于 C++ 的解决方案。无论如何,这就是我想要做的。我有一个在客户端代码中调用的状态机(服务)。
//IStateMachine.h
class IStateMachine
{
public:
bool Run(const std::string& action) = 0;
bool IsTxnValid(const std::string& action)= 0;
}
//StateMachine.h
class StateMachine : public IStateMachine
{
bool Run(const std::string& action) override;
bool IsTxnValid(const std::string& action) override;
}
//StateMachine.cpp
bool StateMachine::IsTxnValid(const std::string& action)
{
//Checks whether the given action is valid for the given state.
}
bool StateMachine::Run(const std::string& action)
{
if(IsTxnValid(action)) // #E
{
//Do processing
return true;
}
return false;
}
//Client.h contains a class Client which has function called RunService.
Client
{
public:
void RunService();
std::unique_ptr<IStateMachine> service_; // Initialised to a non null value in either ctr or
// factory.
}
//Client.cpp
bool Client::RunService(std::string&action)
{
if(!service_->Run(action)) //Run in turn calls IsTxnValid().
{
return false;
}
return true;
}
现在我正在编写一个测试用例来测试 RunService
的功能。我期望如果 Client::IsTxnValid(param)
returns 为假,那么 RunService
.
也应该如此
我已经成功设置了测试配方,可以进行基本测试运行。这是我写的相关测试。在 运行 这个测试中,我得到了错误,即 IsTransitionValid
从未被调用过。
TEST_F(ClientTest, RunService)
{
EXPECT_CALL(*p_service, Run("some_action")); // #A
// EXPECT_CALL(*p_service, Run(testing::_)).WillOnce(::testing::Return(true)); //#B
EXPECT_CALL(*p_service,IsTransitionValid(testing::_)).WillOnce(::testing::Return(false)); //#C : This never gets called.
EXPECT_EQ(false, x_client->RunService());
}
如何正确调用 IsTransitionValid
?
您无需设置此期望值。我会走得更远:你甚至不应该依赖 IStateMachine
中 Run
的实现:你应该只关心它提供的输入(参数,用匹配器检查)和它的输出可以 return(所以基本上只有这两个 classes 之间的合同),这就是它的美妙之处!
它是 StateMachine
class 的实现细节(真正的实现)调用 Run
时所做的事情。您唯一需要在测试中检查的是根据 Run
的结果采取行动。使用三重A规则(安排,行动,断言):你安排测试用例条件(使用EXPECT_CALL
s),然后你行动(调用RunService
)然后你断言(检查[=的结果18=]).
技术细节:
当您通过继承 class Foo
:
创建模拟时
class Foo {
public:
virtual ~Foo() = default;
virtual void bar() = 0;
}
通过定义:
class FooMock : public Foo {
MOCK_METHOD0( bar, void());
}
gmock 将添加 bar
(要覆盖的方法)和 gmock_bar
(gmock 的内部细节)方法到 FooMock
class。 bar
在这种情况下有空的实现。 FooImpl
和 FooMock
共享接口,但有不同的实现 - 因此在 Run
中没有调用 IsTxnValid
:mock class 只是不知道(也不关心)Run
是如何在 StateMachine
中实现的。请记住:在您的测试用例中,您与 StateMachineMock
进行交互,并且您只关心与其 public 接口的交互,这两个 class 之间的契约以及它们如何协同工作。
话虽如此,您当然需要测试 StateMachine
class。它可能依赖于其实现中的另一个接口:将使用不同的模拟集进行测试。但是Client
应该不知道这个。
我是 google 测试框架的初学者,我已经在 SO 上查找了这个问题的解决方案,但找不到任何关于 C++ 的解决方案。无论如何,这就是我想要做的。我有一个在客户端代码中调用的状态机(服务)。
//IStateMachine.h
class IStateMachine
{
public:
bool Run(const std::string& action) = 0;
bool IsTxnValid(const std::string& action)= 0;
}
//StateMachine.h
class StateMachine : public IStateMachine
{
bool Run(const std::string& action) override;
bool IsTxnValid(const std::string& action) override;
}
//StateMachine.cpp
bool StateMachine::IsTxnValid(const std::string& action)
{
//Checks whether the given action is valid for the given state.
}
bool StateMachine::Run(const std::string& action)
{
if(IsTxnValid(action)) // #E
{
//Do processing
return true;
}
return false;
}
//Client.h contains a class Client which has function called RunService.
Client
{
public:
void RunService();
std::unique_ptr<IStateMachine> service_; // Initialised to a non null value in either ctr or
// factory.
}
//Client.cpp
bool Client::RunService(std::string&action)
{
if(!service_->Run(action)) //Run in turn calls IsTxnValid().
{
return false;
}
return true;
}
现在我正在编写一个测试用例来测试 RunService
的功能。我期望如果 Client::IsTxnValid(param)
returns 为假,那么 RunService
.
我已经成功设置了测试配方,可以进行基本测试运行。这是我写的相关测试。在 运行 这个测试中,我得到了错误,即 IsTransitionValid
从未被调用过。
TEST_F(ClientTest, RunService)
{
EXPECT_CALL(*p_service, Run("some_action")); // #A
// EXPECT_CALL(*p_service, Run(testing::_)).WillOnce(::testing::Return(true)); //#B
EXPECT_CALL(*p_service,IsTransitionValid(testing::_)).WillOnce(::testing::Return(false)); //#C : This never gets called.
EXPECT_EQ(false, x_client->RunService());
}
如何正确调用 IsTransitionValid
?
您无需设置此期望值。我会走得更远:你甚至不应该依赖 IStateMachine
中 Run
的实现:你应该只关心它提供的输入(参数,用匹配器检查)和它的输出可以 return(所以基本上只有这两个 classes 之间的合同),这就是它的美妙之处!
它是 StateMachine
class 的实现细节(真正的实现)调用 Run
时所做的事情。您唯一需要在测试中检查的是根据 Run
的结果采取行动。使用三重A规则(安排,行动,断言):你安排测试用例条件(使用EXPECT_CALL
s),然后你行动(调用RunService
)然后你断言(检查[=的结果18=]).
技术细节:
当您通过继承 class Foo
:
class Foo {
public:
virtual ~Foo() = default;
virtual void bar() = 0;
}
通过定义:
class FooMock : public Foo {
MOCK_METHOD0( bar, void());
}
gmock 将添加 bar
(要覆盖的方法)和 gmock_bar
(gmock 的内部细节)方法到 FooMock
class。 bar
在这种情况下有空的实现。 FooImpl
和 FooMock
共享接口,但有不同的实现 - 因此在 Run
中没有调用 IsTxnValid
:mock class 只是不知道(也不关心)Run
是如何在 StateMachine
中实现的。请记住:在您的测试用例中,您与 StateMachineMock
进行交互,并且您只关心与其 public 接口的交互,这两个 class 之间的契约以及它们如何协同工作。
话虽如此,您当然需要测试 StateMachine
class。它可能依赖于其实现中的另一个接口:将使用不同的模拟集进行测试。但是Client
应该不知道这个。