如何对在另一个模拟方法 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

您无需设置此期望值。我会走得更远:你甚至不应该依赖 IStateMachineRun 的实现:你应该只关心它提供的输入(参数,用匹配器检查)和它的输出可以 return(所以基本上只有这两个 classes 之间的合同),这就是它的美妙之处!

它是 StateMachine class 的实现细节(真正的实现)调用 Run 时所做的事情。您唯一需要在测试中检查的是根据 Run 的结果采取行动。使用三重A规则(安排,行动,断言):你安排测试用例条件(使用EXPECT_CALLs),然后你行动(调用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 在这种情况下有空的实现。 FooImplFooMock 共享接口,但有不同的实现 - 因此在 Run 中没有调用 IsTxnValid:mock class 只是不知道(也不关心)Run 是如何在 StateMachine 中实现的。请记住:在您的测试用例中,您与 StateMachineMock 进行交互,并且您只关心与其 public 接口的交互,这两个 class 之间的契约以及它们如何协同工作。

话虽如此,您当然需要测试 StateMachine class。它可能依赖于其实现中的另一个接口:将使用不同的模拟集进行测试。但是Client应该不知道这个。