【问题标题】:Using mocks and death tests使用模拟和死亡测试
【发布时间】:2015-12-04 04:19:33
【问题描述】:

当涉及到死亡测试和对模拟对象的期望时,我发现了 Google 测试的意外行为。

检查以下示例:

#include <gmock/gmock.h>
#include <cassert>

class Interface
{
public:
    virtual void foo() = 0;
};

class InterfaceMock : public Interface
{
public:
    MOCK_METHOD0(foo, void());
};

class Bar
{
public:
    void call(Interface& interface)
    {
        interface.foo();
        assert(false);
    }
};


TEST(BarTest, call_fooGetsCalledAndDies)
{
    InterfaceMock mock;

    EXPECT_CALL(mock, foo());

    ASSERT_DEATH({ Bar().call(mock); }, "");
}

测试失败,因为对 mock.foo() 的预期调用未能断言:

Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BarTest
[ RUN      ] BarTest.call_fooGetsCalledAndDies

[WARNING] /tmp/tmp.sHHkM/gmock-1.7.0/gtest/src/gtest-death-test.cc:825:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
foo.cc:31: Failure
Actual function call count doesn't match EXPECT_CALL(mock, foo())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] BarTest.call_fooGetsCalledAndDies (1 ms)
[----------] 1 test from BarTest (1 ms total)

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

 1 FAILED TEST

有趣的是,如果注释了 EXPECT_CALL(mock, foo()) 行,Google Mock 会针对对 mock.foo() 的意外调用发出警告:

Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BarTest
[ RUN      ] BarTest.call_fooGetsCalledAndDies

[WARNING] /tmp/tmp.sHHkM/gmock-1.7.0/gtest/src/gtest-death-test.cc:825:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.

GMOCK WARNING:
Uninteresting mock function call - returning directly.
    Function call: foo()
Stack trace:
[       OK ] BarTest.call_fooGetsCalledAndDies (1 ms)
[----------] 1 test from BarTest (1 ms total)

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

我猜这在某种程度上与使用fork() 和线程的死亡测试警告有关,但我无法将所有部分匹配在一起。

【问题讨论】:

    标签: c++ unit-testing googletest googlemock


    【解决方案1】:

    这是一个known limitation 的死亡测试。在内部assert_death 分叉,因此在子进程中调用的模拟不会在父进程中注册。如果您希望禁止显示警告,请考虑使用NiceMock

    【讨论】:

    • 关键是我确实关心模拟被调用,所以测试几乎毫无意义。您能否提供对“已知限制”声明的参考? (仅作记录)
    • @AntonioPérez 我似乎记得在其中一个邮件列表上读到过这个,但直到我找到一个具体的声明,check here。关键是模拟函数的调用具有将其标记为被调用的副作用,您在父进程中看不到。
    • 我理解为什么我会因为fork()处理这个过程而得到未满足的期望。但是,为什么我会收到意外调用模拟对象的警告呢?
    • @AntonioPérez 期望(应该调用模拟函数的事实)由子进程继承。如果您省略它,子进程将看到调用是意外的。然而,实际上进行了函数调用的事实并没有传递回父进程。这可能是因为 gtest 将调用信息存储在内存中,而父/子进程之间不共享这些信息。
    • 所以是子进程收到了意外的模拟函数调用,也就是死掉的那个。所以我知道父进程不应该通过调用模拟函数来运行,因此不应该引发警告消息。我显然错过了一些东西。
    【解决方案2】:

    正如上面正确回答的那样,模拟调用没有在子进程中注册。您必须在流程中编写您的 expect_calls。以下应该有效:

    TEST(BarTest, call_fooGetsCalledAndDies)
    {
        InterfaceMock mock;
    
        ASSERT_DEATH({ [](){ EXPECT_CALL(mock, foo());
                             Bar().call(mock);} , "");
    }
    

    【讨论】:

      猜你喜欢
      • 2023-01-22
      • 1970-01-01
      • 2020-03-12
      • 2021-08-24
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      • 1970-01-01
      • 2022-07-12
      相关资源
      最近更新 更多