3

モック オブジェクトとデス テストを使用する googletest 単体テストの 1 つに問題があります。これは、問題を示す最小化されたコード サンプルです。

#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;
}


最後に、この特定のケースを処理する3番目の方法は、リークを許可するのではなく、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_の直前に安全に削除できます。exita

ただし、gtestデステストがどのように機能するかを知らない人にとっては、これは同じ変数が2回削除されたように見え、混乱を引き起こす可能性があります。

于 2012-03-03T00:07:07.013 に答える