Gmock不能模拟在同一个类中调用另一个方法的方法

时间:2023-02-09 10:31:04

I am investigating Gmock (Google Test Framework). I run into an issue which I think Gmock can resolve it but It cannot. Please have a look to:

我正在调查Gmock(谷歌测试框架)。我遇到了一个问题,我认为Gmock可以解决它,但事实并非如此。请看看:

#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

using namespace std;
using ::testing::Invoke;  

//---- THINGS TO TEST ---------
class MyTest {
public:
    void display(const char* str);
    void show_text();
};

void MyTest::display(const char* str){
    cout << __func__<< " " << str << "\n";
    cout << ":-->Inside the display myTest\n";
}

void MyTest::show_text(){
    display("INSIDE MYTEST"); // HOW to mock display() here ?
}
//-------------------------------

//--- Configuration to test myTest ----
template <class myclass>
class Caller {
public:
    myclass T;
    void call_show_text() ;
    void call_display(const char* s) ;
};

template <class myclass>
void Caller<myclass>::call_show_text()
{
    T.show_text();
}

template <class myclass>
void Caller<myclass>::call_display(const char* str)
{
    T.display(str);
}

void my_display(const char* str){
    cout << __func__<< " OUTSIDE MYTEST\n" <<":-->Outside the display myTest\n";
}

struct MockTest {
    MOCK_METHOD1(display, void(const char*));
    MOCK_METHOD0(show_text, void());
};
//-------------------------------

//----- Test cases -------------
//----- Test cases -------------
TEST(TestShowTextMethod, CallDisplayOfmyTest){
    Caller<MyTest> obj1;
    obj1.call_show_text();
}

TEST(TestShowTextMethod, ReroutingDisplayToNewFunctionWithCallDisplay){
    Caller<MockTest> obj2;
    EXPECT_CALL(obj2.T, display("test_obj_2"))
              .Times(1)
              .WillOnce(Invoke(my_display));
    obj2.call_display("test_obj_2");
}

TEST(TestShowTextMethod, ReroutingDisplayToNewFunctionWithCallShowText){
    Caller<MockTest> obj3;
    EXPECT_CALL(obj3.T, display("test_obj_3"))
              .Times(1)
              .WillOnce(Invoke(my_display));
    obj3.call_display("test_obj_3");
}

TEST(TestShowTextMethod, ReroutingToNewFunctionWithCallShowText){
    const char * str = "INSIDE MYTEST";
    Caller<MockTest> obj4;

    EXPECT_CALL(obj4.T, show_text());

    EXPECT_CALL(obj4.T, display(str))
              .Times(1)
              .WillOnce(Invoke(my_display));
    obj4.call_show_text();
}
//-------------------------------

//--- Initialization for test ----
int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Only focus on the 4th test, I think Gmock can handle the fourth TEST: show_text calls display, why I can't mock display in this case ? Is Gmock impossible to mock a method is called in another method in the same class or I made a certain mistake in the 4th testcase ? I got a failed test-result like this:

只关注第4次测试,我认为Gmock可以处理第四次TEST:show_text调用显示,为什么我不能在这种情况下模拟显示? Gmock是不是可以模拟一个方法在同一个类中的另一个方法中调用,或者我在第四个测试用例中犯了一个错误?我得到了一个失败的测试结果,如下所示:

../test_program.cpp:100: Failure
Actual function call count doesn't match EXPECT_CALL(obj4.T, display(str))...
         Expected: to be called once
           Actual: never called - unsatisfied and active

Of course, show_text and display() are exactly called. Does anybody have an idea ?

当然,完全调用show_text和display()。有人有想法吗?

1 个解决方案

#1


3  

why I can't mock display in this case?

为什么我不能在这种情况下模拟显示?

You have not only successfully mocked display but also show_text as well. You should not lean on the behaviour of mocked implementation, because it will not be called.

您不仅可以成功模拟显示,还可以模拟show_text。您不应该依赖于模拟实现的行为,因为它不会被调用。

Is Gmock impossible to mock a method is called in another method in the same class.

Gmock无法模拟一个方法是在同一个类中的另一个方法中调用的。

It is possible, but far from pretty, You can find example below. Note that there are some trade-offs made only for tests. Making DisplayController::display a virtual class is probably the biggest one.

这是可能的,但远非漂亮,你可以在下面找到例子。请注意,仅对测试进行了一些权衡。使DisplayController :: display一个虚拟类可能是最大的一个。

class DisplayController
{
public:
    virtual void display(const std::string& text)
    {

        cout << text << endl;
    }
    void show_str(const std::string& text)
    {
        cout << "Start" << endl;
        display(text);
        cout << "End" << endl;
    }
};

class TestableDisplayController : public DisplayController
{
public:
    MOCK_METHOD1(display, void(const std::string&));
    MOCK_METHOD1(show_str_called, void(const std::string&));

    void show_str(const std::string& text)
    {
        show_str_called(text);
        DisplayController::show_str(text);
    }
};

template <typename T>
class ClassUnderTest
{
public:
    ClassUnderTest(T& display)
        : displayController(display)
    {}

    void callDirectDisplay(const std::string& text)
    {
        displayController.display(text);
    }

    void callIndirectDisplay(const std::string& text)
    {
        displayController.show_str(text);
    }

private:
    T& displayController;
};

TEST(test, example)
{
    TestableDisplayController mockedDisplayController;
    ClassUnderTest<TestableDisplayController> sut(mockedDisplayController);

    std::string l_directDisplay = "directDisplay";
    std::string l_indirectDisplay = "indirectDisplay";

    EXPECT_CALL(mockedDisplayController, display(l_directDisplay));
    sut.callDirectDisplay(l_directDisplay);

    EXPECT_CALL(mockedDisplayController, display(l_indirectDisplay));
    EXPECT_CALL(mockedDisplayController, show_str_called(l_indirectDisplay));

    sut.callIndirectDisplay(l_indirectDisplay);
}

#1


3  

why I can't mock display in this case?

为什么我不能在这种情况下模拟显示?

You have not only successfully mocked display but also show_text as well. You should not lean on the behaviour of mocked implementation, because it will not be called.

您不仅可以成功模拟显示,还可以模拟show_text。您不应该依赖于模拟实现的行为,因为它不会被调用。

Is Gmock impossible to mock a method is called in another method in the same class.

Gmock无法模拟一个方法是在同一个类中的另一个方法中调用的。

It is possible, but far from pretty, You can find example below. Note that there are some trade-offs made only for tests. Making DisplayController::display a virtual class is probably the biggest one.

这是可能的,但远非漂亮,你可以在下面找到例子。请注意,仅对测试进行了一些权衡。使DisplayController :: display一个虚拟类可能是最大的一个。

class DisplayController
{
public:
    virtual void display(const std::string& text)
    {

        cout << text << endl;
    }
    void show_str(const std::string& text)
    {
        cout << "Start" << endl;
        display(text);
        cout << "End" << endl;
    }
};

class TestableDisplayController : public DisplayController
{
public:
    MOCK_METHOD1(display, void(const std::string&));
    MOCK_METHOD1(show_str_called, void(const std::string&));

    void show_str(const std::string& text)
    {
        show_str_called(text);
        DisplayController::show_str(text);
    }
};

template <typename T>
class ClassUnderTest
{
public:
    ClassUnderTest(T& display)
        : displayController(display)
    {}

    void callDirectDisplay(const std::string& text)
    {
        displayController.display(text);
    }

    void callIndirectDisplay(const std::string& text)
    {
        displayController.show_str(text);
    }

private:
    T& displayController;
};

TEST(test, example)
{
    TestableDisplayController mockedDisplayController;
    ClassUnderTest<TestableDisplayController> sut(mockedDisplayController);

    std::string l_directDisplay = "directDisplay";
    std::string l_indirectDisplay = "indirectDisplay";

    EXPECT_CALL(mockedDisplayController, display(l_directDisplay));
    sut.callDirectDisplay(l_directDisplay);

    EXPECT_CALL(mockedDisplayController, display(l_indirectDisplay));
    EXPECT_CALL(mockedDisplayController, show_str_called(l_indirectDisplay));

    sut.callIndirectDisplay(l_indirectDisplay);
}