Модульное тестирование и Google Mock Владимир Лосев Google [email_address] Yet Another Conference 2011 Москва, 19 сентября 1
Agenda Почему Google Mock? Как им пользоваться Примеры 2
Хочешь жить без багов? Спроси меня как! Ошибки снижают производительность ...Если не чинить их быстро Нужны автоматизированные тесты Быстрые Надёжные Точные Тестируем по одному модулю за раз 3
Изоляция модулей В программах на C++ абстрагируем взаимодействия между объектами через интерфейсы Используем тестовые двойники (stub-, mock-объекты, и т.д.) для имитации поведения соседей Используем метод внедрения зависимостей для добавления двойников 4
Внедрение зависимостей class SocketInterface {  public:    virtual int Read(void* buffer, int size) = 0; }; class Server {   public:    Server(SocketInterface* socket) : socket_(socket) {}    bool ReadRequest (string* result) {      char buffer[BUFFER_SIZE];      int bytes_read;      while ((bytes_read =  socket->Read (buffer,                                        BUFFER_SIZE)) > 0)        result->append(buffer, buffer + bytes_read);      return result->size() > 0;    }   private:    SocketInterface* const socket_; }; 5
class MockSocket : public SocketInterface {   public:    MockSocket(const char* buffer_to_read, int buffer_size)        : buffer_to_read_(buffer_to_read_), size_(buffer_size),          bytes_read_(0) {    }    virtual int Read (void* buffer, int n) {      int actual_read = std::min(n, size_ - bytes_read_);      memcpy(buffer, buffer_to_read_ + bytes_read_, actual_read);      bytes_read_ += actual_read;      return actual_read;    }    int bytes_read() const { return bytes_read_; } private:    const char* buffer_to_read_;    int size_;    int bytes_read_; }; Mock-объект, написанный вручную 6
Тест с таким объектом TEST(Server_ReadRequest, ReadsCompleteRequest) {    string data("1234567890123456789012345");    MockSocket mock_socket(data.data(), data.size());    Server server(&mock_socket);    string buffer;    EXPECT_TRUE(server.ReadRequest(&buffer));    EXPECT_EQ(data, buffer); } Проверяет только результат, а не взаимодействие 7
Google Mock Google C++ Mocking Framework/Google Mock/gMock Написан в 2007 г. Жаньонгом Ваном (Zhanyong Wan) Код открыт в 2008 г. Лежит на  code.google.com/p/googlemock Используется во многих проектах с открытым кодом (Chromium, LLVM) 8
Нужна библиотека для написания тестов Хорошо интегрирован с Google Test Лежит на  http://code.google.com/p/googletest Позволяет легко и быстро писать тесты:    #include <gtest/gtest.h>    TEST(MathTest, ArithmeticsStillWorks) {      EXPECT_EQ(4, 2 * 2);    } 9
Mock-объект на Google Mock  class MockSocket : public SocketInterface {   public:    MOCK_METHOD2(Read, int(void* buffer, int n)); }; 10
Определение ожиданий  class MockSocket : public SocketInterface {   public:    MOCK_METHOD2(Read, int(void* buffer, int n)); };    EXPECT_CALL(mock_socket, Read(…)) 11
Описние параметров class MockSocket : public SocketInterface {   public:    MOCK_METHOD2(Read, int(void* buffer, int n)); };    EXPECT_CALL(mock_socket, Read(_, Ge(25))) 12
Описание количества вызовов  class MockSocket : public SocketInterface {   public:    MOCK_METHOD2(Read, int(void* buffer, int n)); };    EXPECT_CALL(mock_socket, Read(_, Ge(25)))        .Times(2) 13
Описание поведения class MockSocket : public SocketInterface {   public:    MOCK_METHOD2(Read, int(void* buffer, int n)); };    string data(&quot;1234567890123456789012345&quot;);    EXPECT_CALL(mock_socket, Read(_, Ge(25)))        .Times(2)        .WillOnce(DoAll(CopyData(data),                        Return(data.size())))        .WillOnce(Return(0)); 14
Полный тест class MockSocket : public SocketInterface {   public:    MOCK_METHOD2(Read, int(void* buffer, int n)); }; TEST(Server_ReadRequest, ReadsCompleteRequest) {    MockSocket mock_socket;    string data(&quot;1234567890123456789012345&quot;);    EXPECT_CALL(mock_socket, Read(_, Ge(25)))        .Times(2)        .WillOnce(DoAll(CopyData(data),                        Return(data.size())))        .WillOnce(Return(0));    Server server(&mock_socket);    string result;    EXPECT_TRUE(server.ReadRequest(&result));    EXPECT_EQ(data, result); } 15
Предикаты ...на стероидах Проверяют условия Описывают эти условия Предоставляют объяснения Примеры: Простые:  42, _, Gt(32), NotNull() Составные:  AllOf(m1, ...), AnyOf(m1, ...), Not(matcher) Для контейнеров:  Contains(matcher), Each(matcher) ElementsAre(e1, ..., en), ElementsAreArray(arr) Можно определять собственные 16
Количество вызовов Указывается в методе Times():    EXPECT_CALL(mock, Foo()). Times(cardinality) ; Можно указывать: 2 Exactly(2) AtLeast(3) AtMost(5) Between(3, 4) 17
Порядок По умолчанию порядок вызовов не задаётся Можно указывать полный или частичный порядок Отсутствие циклов гаранировано {    InSequence s;    EXPECT_CALL(mock, A());    EXPECT_CALL(mock, B()); } Sequence s1, s2; EXPECT_CALL(mock, A()).InSequence(s1, s2); EXPECT_CALL(mock, B()).InSequence(s1); EXPECT_CALL(mock, C()).InSequence(s2); 18
Действия Определяются в методах WillOnce() и WillRepeatedly()  Определяют поведение mock-объекта Статически типизированы (type-safe) SetArrayArgument<>(), SetArg<>(), SaveArg<>(), Return(value), ReturnRef(object), Invoke(function), Invoke(object, method) Составные:  DoAll(action1, action2, ...) Можно определять самому ON_CALL() определяет действие по умолчанию чтобы можно было не указывать WillOnce или WillRepeatedly 19
Расширяем Google Mock – предикаты MATCHER(IsEven, &quot;&quot;) { return arg % 2 == 0; } MATCHER_P(IsDivisibleBy, n, &quot;&quot;) {    return arg % n == 0; } MATCHER_P2(IsSumOf, a, b, &quot;&quot;) {    return arg == a + b; } EXPECT_CALL(mock, Foo(IsSumOf(x, 7))); Не должны вызывать сторонних эффектов Не должны содержать изменяемого состояния Есть более продвинутое API для создания предикатов 20
Расширяем Google Mock – действия ACTION(ChooseCallee) {    if (arg0)      arg1->f();    else      arg2->g(); } ACTION_P(CopyData, data) {    std::copy(data.data(),              data.data() + data.size(),              arg0); } Доступ к аргументам метода: arg0, arg1, ... Есть более продвинутое API для создания действий 21
Пример: внедрение ошибок TEST(FileReaderTest, HandlesConnectionClosed) {    MockSocket mock_socket;    MockServerManager mock_server_manager;    EXPECT_CALL(mock_socket, Read(_, Ge(25))        .WillOnce( SetErrnoAndReturn (EPIPE, -1));    EXPECT_CALL(mock_server_manager, OnConnectionLost());    Server server(&mock_socket, &mock_server_manager);    EXPECT_FALSE(reader.ReadRequest(&result)); } 22
Пример: быстрый сон class WallClockInterface {   public:    virtual time_t GetWallTime() const = 0;    virtual void SleepMilliseconds(time_t ms) = 0; }; class MockWallClock : public WallClockInterface {   public:    MOCK_CONST_METHOD0(GetWallTime, time_t());    MOCK_METHOD1(SleepMilliseconds, void()); }; 23
Пример: быстрый сон TEST(NetworkClientTest, WaitsAndRetries) {    MockWallClock mock_clock;    MockSocket mock_socket;    InSequence s;    EXPECT_CALL(mock_socket, Connect(_))        .WillOnce(Return(false));    EXPECT_CALL(mock_clock,  GetWallTime ())        .WillOnce( Return(1000) );    EXPECT_CALL(mock_clock,  SleepMilliseconds(2000) );    EXPECT_CALL(mock_clock,  GetWallTime ())        .WillOnce( Return(3000) );    EXPECT_CALL(mock_socket,  Connect(_) )        .WillOnce(Return(true));    NetworkClient client(&mock_clock, &mock_socket);    EXPECT_TRUE(client.AttemptConnectWithRetry()); } 24
Преимущества Проверяет взаимодействие между объектом и соседями Позволяет писать быстрые тесты Позволяет писать надёжные тесты Упрощает тестирование кода обработки ошибок Позволяет писать код, не имея соседей 25
Недостатки Mock-объекты компилируются медленно Малопонятная диагностика Написан Google Mock Doctor, скрипт для интерпретации диагностики (GCC и LLVM) Mock-нужно писать вручную Есть скрипт для генерации mock-классов из определений интерфейсов или классов 26
Google Mock http://code.google.com/p/googlemock http://code.google.com/p/googlemock/wiki/Documentation googlemock@googlegroups.com (English) 27