2016-04-10 8 views
3

Ich untersuche Gmock (Google Test Framework). Ich laufe auf ein Problem, das ich denke Gmock kann es lösen, aber es kann nicht. Weitere Informationen finden sie auf:Gmock kann nicht eine Methode vortäuschen, die eine andere Methode in der gleichen Klasse anrief

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

using namespace std; 
using ::testing::Invoke; 

//---- THINGS TO TEST --------- 
class MyTest { 
public: 
    void display(const char* str); 
    void show_text(); 
}; 

void MyTest::display(const char* str){ 
    cout << __func__<< " " << str << "\n"; 
    cout << ":-->Inside the display myTest\n"; 
} 

void MyTest::show_text(){ 
    display("INSIDE MYTEST"); // HOW to mock display() here ? 
} 
//------------------------------- 

//--- Configuration to test myTest ---- 
template <class myclass> 
class Caller { 
public: 
    myclass T; 
    void call_show_text() ; 
    void call_display(const char* s) ; 
}; 

template <class myclass> 
void Caller<myclass>::call_show_text() 
{ 
    T.show_text(); 
} 

template <class myclass> 
void Caller<myclass>::call_display(const char* str) 
{ 
    T.display(str); 
} 

void my_display(const char* str){ 
    cout << __func__<< " OUTSIDE MYTEST\n" <<":-->Outside the display myTest\n"; 
} 

struct MockTest { 
    MOCK_METHOD1(display, void(const char*)); 
    MOCK_METHOD0(show_text, void()); 
}; 
//------------------------------- 

//----- Test cases ------------- 
//----- Test cases ------------- 
TEST(TestShowTextMethod, CallDisplayOfmyTest){ 
    Caller<MyTest> obj1; 
    obj1.call_show_text(); 
} 

TEST(TestShowTextMethod, ReroutingDisplayToNewFunctionWithCallDisplay){ 
    Caller<MockTest> obj2; 
    EXPECT_CALL(obj2.T, display("test_obj_2")) 
       .Times(1) 
       .WillOnce(Invoke(my_display)); 
    obj2.call_display("test_obj_2"); 
} 

TEST(TestShowTextMethod, ReroutingDisplayToNewFunctionWithCallShowText){ 
    Caller<MockTest> obj3; 
    EXPECT_CALL(obj3.T, display("test_obj_3")) 
       .Times(1) 
       .WillOnce(Invoke(my_display)); 
    obj3.call_display("test_obj_3"); 
} 

TEST(TestShowTextMethod, ReroutingToNewFunctionWithCallShowText){ 
    const char * str = "INSIDE MYTEST"; 
    Caller<MockTest> obj4; 

    EXPECT_CALL(obj4.T, show_text()); 

    EXPECT_CALL(obj4.T, display(str)) 
       .Times(1) 
       .WillOnce(Invoke(my_display)); 
    obj4.call_show_text(); 
} 
//------------------------------- 

//--- Initialization for test ---- 
int main(int argc, char** argv) { 
    ::testing::InitGoogleTest(&argc, argv); 
    return RUN_ALL_TESTS(); 
} 

Erst am 4. Test konzentrieren, denke ich Gmock den vierten Test umgehen kann: show_textdisplay nennt, warum ich nicht display in diesem Fall verspotten? Ist Gmock im möglich, eine Methode zu verspotten, wird in einer anderen Methode in der gleichen Klasse oder genannt Ich machte einen bestimmten Fehler im 4. Testfall? Ich bekam einen fehlgeschlagenen Test-Ergebnis wie folgt aus:

../test_program.cpp:100: Failure 
Actual function call count doesn't match EXPECT_CALL(obj4.T, display(str))... 
     Expected: to be called once 
      Actual: never called - unsatisfied and active 

Natürlich show_text und display() sind genau genannt. Hat jemand eine Idee?

Antwort

3

Warum kann ich display in diesem Fall nicht spotten?

Sie haben nicht nur erfolgreich display sondern auch show_text verspottet. Sie sollten sich nicht auf das Verhalten einer verspotteten Implementierung stützen, da es nicht aufgerufen wird.

Ist Gmock unmöglich, eine Methode zu verspotten, wird in einer anderen Methode in der gleichen Klasse aufgerufen.

Es ist möglich, aber weit von hübsch, Sie können Beispiel unten finden. Beachten Sie, dass einige Kompromisse nur für Tests gemacht werden. DisplayController :: eine virtuelle Klasse anzuzeigen ist wahrscheinlich die größte.

class DisplayController 
{ 
public: 
    virtual void display(const std::string& text) 
    { 

     cout << text << endl; 
    } 
    void show_str(const std::string& text) 
    { 
     cout << "Start" << endl; 
     display(text); 
     cout << "End" << endl; 
    } 
}; 

class TestableDisplayController : public DisplayController 
{ 
public: 
    MOCK_METHOD1(display, void(const std::string&)); 
    MOCK_METHOD1(show_str_called, void(const std::string&)); 

    void show_str(const std::string& text) 
    { 
     show_str_called(text); 
     DisplayController::show_str(text); 
    } 
}; 

template <typename T> 
class ClassUnderTest 
{ 
public: 
    ClassUnderTest(T& display) 
     : displayController(display) 
    {} 

    void callDirectDisplay(const std::string& text) 
    { 
     displayController.display(text); 
    } 

    void callIndirectDisplay(const std::string& text) 
    { 
     displayController.show_str(text); 
    } 

private: 
    T& displayController; 
}; 

TEST(test, example) 
{ 
    TestableDisplayController mockedDisplayController; 
    ClassUnderTest<TestableDisplayController> sut(mockedDisplayController); 

    std::string l_directDisplay = "directDisplay"; 
    std::string l_indirectDisplay = "indirectDisplay"; 

    EXPECT_CALL(mockedDisplayController, display(l_directDisplay)); 
    sut.callDirectDisplay(l_directDisplay); 

    EXPECT_CALL(mockedDisplayController, display(l_indirectDisplay)); 
    EXPECT_CALL(mockedDisplayController, show_str_called(l_indirectDisplay)); 

    sut.callIndirectDisplay(l_indirectDisplay); 
} 
+0

Vielen Dank. Großartig, es hat funktioniert. Aber ich habe ein Problem, ich kann die Quelle in meinem Projekt nicht ändern, das "virtuelle" ist nicht erlaubt. Also werde ich mein Projekt anpassen. Trotzdem danke. –

Verwandte Themen