29 października 2012

StrictMock i referencja w konstruktorze [TRICK]

Napotkałem ostatnio taki problem (mowa tu o testach charakteryzacyjnych).

Przykład: Chcemy przetestować metodę Filter::run(). Klasa do działania potrzebuje obiektów Inc i Show. Nie mają one czysto abstrakcyjnych interfejsów (ale zrobimy dla nich mocki). Show potrzebuje do działania referencji do Inc.

Problem pojawia się, gdy mock zrobimy StrictMock-iem i będziemy chcieli go jeszcze zainicjować. Tutaj ShowMock chcemy zainicjować IncMock (linijka 49-50).
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/ref.hpp>
#include <gmock/gmock.h>

using namespace std;
using namespace ::testing;

class Inc {
public:
    virtual int inc(int v) { return v++; }
};

class IncMock : public Inc {
public:
    MOCK_METHOD1(inc, int(int));
};

class Show {
    Inc& obj;
public:
    Show(Inc& i) : obj(i) {}
    virtual void show(int v) { cout << "Val: " << obj.inc(v) << endl; }
};

class ShowMock : public Show {
public:
    ShowMock(Inc& i) : Show(i) {}
    MOCK_METHOD1(show, void(int));
};

class Filter {
    boost::shared_ptr<Show> sw;
    boost::shared_ptr<Inc> in;
public:
    Filter(boost::shared_ptr<Show> s, 
           boost::shared_ptr<Inc> i) : sw(s), in(i) {}
    void run(int val) {
        if (val > 5)
            sw->show(val);
        in->inc(val);
    }
};

TEST(FilterTest, test) {
    boost::shared_ptr<IncMock> l_incMock(new StrictMock<IncMock>());

//  NOT WORKING
//  boost::shared_ptr<ShowMock> l_showMock(new StrictMock<ShowMock>
//                                           (*l_incMock));
//  NOT WORKING
//  boost::shared_ptr<ShowMock> l_showMock(new StrictMock<ShowMock>
//                                           (boost::cref(*l_incMock)));

    boost::shared_ptr<ShowMock> l_showMock(new StrictMock<ShowMock>
                                             (boost::ref(*l_incMock)));
    Filter l_filter(l_showMock, l_incMock);

    int l_val = 8;
    EXPECT_CALL(*l_incMock, inc(l_val)).WillOnce(Return(l_val + 1));
    EXPECT_CALL(*l_showMock, show(l_val));

    l_filter.run(l_val);
}

int main(int argc, char *argv[]) {
    ::testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}
Pierwsze rozwiązanie wypluje error przy kompilacji
In file included from /home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock.h:64:0,
                 from main.cpp:4:
/home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock-generated-nice-strict.h: In constructor ‘testing::StrictMock<M>::StrictMock(const A1&) [with A1 = IncMock, MockClass = ShowMock]’:
main.cpp:48:77:   instantiated from here
/home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock-generated-nice-strict.h:174:51: error: no matching function for call to ‘ShowMock::ShowMock(const IncMock&)’
/home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock-generated-nice-strict.h:174:51: note: candidates are:
main.cpp:28:5: note: ShowMock::ShowMock(Inc&)
main.cpp:28:5: note:   no known conversion for argument 1 from ‘const IncMock’ to ‘Inc&’
main.cpp:26:7: note: ShowMock::ShowMock(const ShowMock&)
main.cpp:26:7: note:   no known conversion for argument 1 from ‘const IncMock’ to ‘const ShowMock&’
Co się okazuje, StrictMock ma tylko konstruktory explicit, dlatego podziała trick z boost::ref().
template <typename A1>
explicit StrictMock(const A1& a1) : MockClass(a1) {
  ::testing::Mock::FailUninterestingCalls(
      internal::ImplicitCast_<MockClass*>(this));
}
Niestety nie wiem dlaczego nie działa boost::cref() ?!

Brak komentarzy:

Prześlij komentarz