为什么使用取消引用的指针时,EXPECT_CALL测试意外通过?

问题描述:

我刚开始使用GoogleTest和GoogleMock。读"for dummies" documentation的示例测试一个Painter类取决于一个Turtle上:为什么使用取消引用的指针时,EXPECT_CALL测试意外通过?

实物 - Turtle.h

class Turtle { 
public: 
    virtual ~Turtle() {} 
    virtual void PenDown() = 0; 
}; 

模仿对象 - 模拟turtle.h

class MockTurtle : public Turtle { 
public: 
    MOCK_METHOD0(PenDown, void()); 
}; 

测试中的代码 - Painter.h

class Painter { 
public: 
    Painter(Turtle *turtle){}; 
}; 

单元测试 - test_painter.cpp

这是为了测试是否turtle.PenDown()方法是从Painter构造函数调用。

TEST(PainterTest, CanDrawSomething) { 
    MockTurtle turtle; 
    EXPECT_CALL(turtle, PenDown()) 
      .Times(AtLeast(1)); 
    Painter painter(&turtle); 
} 

该测试正确失败,因为PenDown()永远不会被调用。

但是,如果我更改测试使用取消引用指针MockTurtle不正确通过。

TEST(PainterTest, CanDrawSomething) { 
    MockTurtle *turtle = new MockTurtle(); 
    EXPECT_CALL(*turtle, PenDown()) 
      .Times(AtLeast(1)); 

    Painter painter(turtle); 
} 

为什么使用取消引用的指针时该测试通过?在我的代码中没有任何地方是PenDown()

欲了解更多的上下文,我想使用一个指针MockTurtle,以便我可以在测试夹具中初始化它,以便其他测试可以使用它。

+0

我正在使用Google Test的最新版本,并且按预期工作。尝试使用Google Test的最新版本 – Asesh

+0

我也在使用最新版本的Google Test(从github取得)。你在做什么特别的东西来构建你的测试可执行程我的构建命令是:'g ++ -I googlemock/include -I googletest/include -I ../source -L googlemock -lgmock_main test_painter.cpp -o test_painter' – donturner

+0

没什么特别的,但我使用Visual C++,这里两个测试都失败 – Asesh

你不会删除你的指针。

并不是忘记删除它会导致PenDown()被推送。该成员从未被调用。但是它将结果报告给框架的析构函数MockTurtle

当你泄漏它时,没有报告。框架认为你运行了一个空测试(真空通过),因为它没有得到任何反馈。

turtle是一个具有自动存储持续时间的对象(不是指针)时,其析构函数在范围exit处自动调用。这就是报告错误的原因。

这只是GoogleMock利用RAII作为样板。

除了@ StoryTeller的出色答案之外,我认为增加一些额外的背景会非常有用,所以没有人会被这个问题所困扰。

我正在使用CLion作为我的测试运行器,并且因为this bug发生了之后的错误测试已经运行未显示。从终端运行我的测试二进制文件显示它:

./test_painter --gtest_filter=* --gtest_color=no 
Running main() from gmock_main.cc 
[==========] Running 1 test from 1 test case. 
[----------] Global test environment set-up. 
[----------] 1 test from PainterTest 
[ RUN  ] PainterTest.CanDrawSomething 
[  OK ] PainterTest.CanDrawSomething (0 ms) 
[----------] 1 test from PainterTest (0 ms total) 

[----------] Global test environment tear-down 
[==========] 1 test from 1 test case ran. (0 ms total) 
[ PASSED ] 1 test. 

/Users/donturner/PCode/workspace-kinetis/blinky/tests/test_painter.cpp:13: ERROR: this mock object (used in test PainterTest.CanDrawSomething) should be deleted but never is. Its address is @0x7fc06f402720. 
ERROR: 1 leaked mock object found at program exit. 

所以我忘了删除我的指针。添加以下行到我的测试结束:

delete turtle; 

和变戏法似的测试无误失败:

$ ./test_painter --gtest_filter=* --gtest_color=no 
Running main() from gmock_main.cc 
[==========] Running 1 test from 1 test case. 
[----------] Global test environment set-up. 
[----------] 1 test from PainterTest 
[ RUN  ] PainterTest.CanDrawSomething 
/Users/donturner/PCode/workspace-kinetis/blinky/tests/test_painter.cpp:13: Failure 
Actual function call count doesn't match EXPECT_CALL(*turtle, PenDown())... 
     Expected: to be called at least once 
      Actual: never called - unsatisfied and active 
[ FAILED ] PainterTest.CanDrawSomething (0 ms) 
[----------] 1 test from PainterTest (0 ms total) 

[----------] Global test environment tear-down 
[==========] 1 test from 1 test case ran. (0 ms total) 
[ PASSED ] 0 tests. 
[ FAILED ] 1 test, listed below: 
[ FAILED ] PainterTest.CanDrawSomething 

1 FAILED TEST 

如果有人能告诉我为什么忘记删除指针导致PenDown()被称为我会最感兴趣的!

+0

雅,现在我可以复制这个问题。听起来很有趣 – Asesh