2012-03-02 4 views
2

モックオブジェクトと死のテストを使用して私のgoogletest unittestsの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. 

それは右EXPECT_DEATH表明した後、ヒープ上のモックオブジェクトの上に左用googlemockチェックのように思えるが、aを削除呼び出される関数でaが使用される可能性があるため、マクロを呼び出す前には明らかに良い解決策ではありません。実際には、テストスイートの解体の終わりにチェックが行われると思います。私は何が欠けていますか?

+0

おそらく、子プロセスの終了によって、プログラムはmockオブジェクトを削除せずに終了することになりますが、mockオブジェクトのクリーンアップルーチンはリークチェックを行います。私はabort()を出口の代わりに使用しようとしています – PlasmaHH

+0

実際には 'abort()'を使って動作しますが、これはあまり役に立ちませんが、プロダクションコードの特定のエラーコードをチェックしたいのです。 – jupp0r

+0

私は死のテストがそれのために作られたとは思わない、彼らはちょうど何かがクラッシュすることを保証する必要があります。たぶん、例外をスローして、特定の例外がスローされたことを確認したいでしょうか? – PlasmaHH

答えて

2

aが漏洩されますので、あなたはこのことについてgmockを指示する必要があります:あなたはまた、すべてのgmockリーク検出をオフにする::testing::FLAGS_gmock_catch_leaked_mocks = false;を使用することができますが、これはおそらくに入るために悪い習慣です

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


。しかし、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; 
} 


最後に、この特別な場合を処理するための第三の方法は、それがリークすることを可能にするのではなくB::kill()delete a_;です。

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は死のテストを実行するための新しいプロセスを生成しますので、あなたはまた、テスト・フィクスチャ内aを削除しながら、ちょうどexit ING前a_を削除しても安全です。

しかし、どのようにgtestの死のテストが動作しているかわからない人には、同じ変数が2回削除されるように見え、混乱を招く可能性があります。

+0

質問があります:なぜgooglemockは死のテストの終わりに削除されたものをチェックしますか?これはバグではありませんか? – jupp0r

+0

私はそうは思わない。 gmockはおそらくオブジェクトの破壊がgtestの死のテストの文脈にあることに気付いていないでしょう。また、死亡テストは、オブジェクトが適切に削除された、優雅なアプリケーション終了のテストでもあります。リークのチェックをデフォルトにすることはgmockの最良の選択肢のようです。特に、必要に応じてこの動作を明示的に無効にすることができるからです。 – Fraser