3

我的一个使用模拟对象和死亡测试的 googletest 单元测试有问题。这是说明问题的最小化代码示例:

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

using namespace ::testing;

class MockA {
  public:
    MockA() {};
    virtual ~MockA() {};

    MOCK_METHOD1(bla,int(int));
};


class B {
  public:
    B(MockA * a)
            : a_(a) {};
    void kill() {
        exit(1);
    }
    MockA * a_;
};

TEST(BDeathTest,BDies) {
    MockA * a = new MockA();
    ON_CALL(*a,bla(_)).WillByDefault(Return(1));
    B * b = new B(a);
    EXPECT_DEATH(b->kill(),"");
    delete a;
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

输出:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BDeathTest
[ RUN      ] BDeathTest.BDies

gtest.cc:27: ERROR: this mock object (used in test BDeathTest.BDies) should be deleted but never is. Its address is @0x7fe453c00ec0.
ERROR: 1 leaked mock object found at program exit.
[       OK ] BDeathTest.BDies (2 ms)
[----------] 1 test from BDeathTest (2 ms total)

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

似乎 googlemock 在EXPECT_DEATH断言之后立即检查堆上剩余的模拟对象,但在调用宏之前删除a显然不是一个好的解决方案,因为a可能在被调用的函数中使用。我实际上希望在测试套件解构结束时进行检查。我错过了什么?

4

1 回答 1

2

由于a会被泄露,你需要告诉 gmock:

TEST(BDeathTest,BDies) {
    MockA * a = new MockA;
    ON_CALL(*a,bla(_)).WillByDefault(Return(1));
    B * b = new B(a);
    Mock::AllowLeak(a);  // <=== Self-explanatory addition
    EXPECT_DEATH(b->kill(),"");
    delete a;
    delete b;
}


您也可以使用::testing::FLAGS_gmock_catch_leaked_mocks = false;关闭所有 gmock 泄漏检测,但这可能是一个坏习惯。但是,如果您在调用exit(). 如果测试继续进行进一步的工作,也值得立即重新打开它EXPECT_DEATH(尽管在上面的示例中,重新打开它是没有意义的)。

TEST(BDeathTest,BDies) {
    MockA * a = new MockA;
    ON_CALL(*a,bla(_)).WillByDefault(Return(1));
    B * b = new B(a);
    FLAGS_gmock_catch_leaked_mocks = false;  // <=== Switch off mock leak checking
    EXPECT_DEATH(b->kill(),"");
    FLAGS_gmock_catch_leaked_mocks = true;  // <=== Re-enable mock leak checking
                                            //      in case the test is refactored
    delete a;
    delete b;
}


最后,处理这种特殊情况的第三种方法是进入delete a_;B::kill()不是让它泄漏。

class B {
    ...
    void kill() {
        delete a_;
        exit(1);
    }
    MockA * a_;
};

TEST(BDeathTest,BDies) {
    MockA * a = new MockA;
    ON_CALL(*a,bla(_)).WillByDefault(Return(1));
    B * b = new B(a);
    EXPECT_DEATH(b->kill(),"");
    delete a;
    delete b;
}

由于 gtest 生成了一个新进程来执行死亡测试,因此您可以安全地在 inga_之前删除exit,同时a在测试夹具内删除。

但是,对于不知道 gtest 死亡测试如何工作的人来说,这看起来像是同一个变量被删除了两次,并且可能会引起混淆。

于 2012-03-03T00:07:07.013 回答