Модульное тестирование и 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

Юнит-тестирование и Google Mock. Влад Лосев, Google

  • 1.
      Модульное тестированиеи Google Mock Владимир Лосев Google [email_address] Yet Another Conference 2011 Москва, 19 сентября 1
  • 2.
    Agenda Почему GoogleMock? Как им пользоваться Примеры 2
  • 3.
    Хочешь жить безбагов? Спроси меня как! Ошибки снижают производительность ...Если не чинить их быстро Нужны автоматизированные тесты Быстрые Надёжные Точные Тестируем по одному модулю за раз 3
  • 4.
    Изоляция модулей Впрограммах на C++ абстрагируем взаимодействия между объектами через интерфейсы Используем тестовые двойники (stub-, mock-объекты, и т.д.) для имитации поведения соседей Используем метод внедрения зависимостей для добавления двойников 4
  • 5.
    Внедрение зависимостей classSocketInterface {  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
  • 6.
    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
  • 7.
    Тест с такимобъектом TEST(Server_ReadRequest, ReadsCompleteRequest) {   string data(&quot;1234567890123456789012345&quot;);   MockSocket mock_socket(data.data(), data.size());   Server server(&mock_socket);   string buffer;   EXPECT_TRUE(server.ReadRequest(&buffer));   EXPECT_EQ(data, buffer); } Проверяет только результат, а не взаимодействие 7
  • 8.
    Google Mock GoogleC++ Mocking Framework/Google Mock/gMock Написан в 2007 г. Жаньонгом Ваном (Zhanyong Wan) Код открыт в 2008 г. Лежит на  code.google.com/p/googlemock Используется во многих проектах с открытым кодом (Chromium, LLVM) 8
  • 9.
    Нужна библиотека длянаписания тестов Хорошо интегрирован с Google Test Лежит на  http://code.google.com/p/googletest Позволяет легко и быстро писать тесты:   #include <gtest/gtest.h>   TEST(MathTest, ArithmeticsStillWorks) {     EXPECT_EQ(4, 2 * 2);   } 9
  • 10.
    Mock-объект на GoogleMock  class MockSocket : public SocketInterface {   public:   MOCK_METHOD2(Read, int(void* buffer, int n)); }; 10
  • 11.
    Определение ожиданий  classMockSocket : public SocketInterface {   public:   MOCK_METHOD2(Read, int(void* buffer, int n)); };   EXPECT_CALL(mock_socket, Read(…)) 11
  • 12.
    Описние параметров classMockSocket : public SocketInterface {   public:   MOCK_METHOD2(Read, int(void* buffer, int n)); };   EXPECT_CALL(mock_socket, Read(_, Ge(25))) 12
  • 13.
    Описание количества вызовов class MockSocket : public SocketInterface {   public:   MOCK_METHOD2(Read, int(void* buffer, int n)); };   EXPECT_CALL(mock_socket, Read(_, Ge(25)))       .Times(2) 13
  • 14.
    Описание поведения classMockSocket : 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
  • 15.
    Полный тест classMockSocket : 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
  • 16.
    Предикаты ...на стероидахПроверяют условия Описывают эти условия Предоставляют объяснения Примеры: Простые: 42, _, Gt(32), NotNull() Составные: AllOf(m1, ...), AnyOf(m1, ...), Not(matcher) Для контейнеров:  Contains(matcher), Each(matcher) ElementsAre(e1, ..., en), ElementsAreArray(arr) Можно определять собственные 16
  • 17.
    Количество вызовов Указываетсяв методе Times():   EXPECT_CALL(mock, Foo()). Times(cardinality) ; Можно указывать: 2 Exactly(2) AtLeast(3) AtMost(5) Between(3, 4) 17
  • 18.
    Порядок По умолчаниюпорядок вызовов не задаётся Можно указывать полный или частичный порядок Отсутствие циклов гаранировано {   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
  • 19.
    Действия Определяются вметодах 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
  • 20.
    Расширяем 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
  • 21.
    Расширяем 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
  • 22.
    Пример: внедрение ошибок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
  • 23.
    Пример: быстрый сон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
  • 24.
    Пример: быстрый сон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.
    Преимущества Проверяет взаимодействиемежду объектом и соседями Позволяет писать быстрые тесты Позволяет писать надёжные тесты Упрощает тестирование кода обработки ошибок Позволяет писать код, не имея соседей 25
  • 26.
    Недостатки Mock-объекты компилируютсямедленно Малопонятная диагностика Написан Google Mock Doctor, скрипт для интерпретации диагностики (GCC и LLVM) Mock-нужно писать вручную Есть скрипт для генерации mock-классов из определений интерфейсов или классов 26
  • 27.
    Google Mock http://code.google.com/p/googlemockhttp://code.google.com/p/googlemock/wiki/Documentation googlemock@googlegroups.com (English) 27

Editor's Notes

  • #4 Finding and fixing bugs takes significant portion of programmer&apos;s time, killing productivity.
  • #7 18 lines
  • #15 * Copy Data is magic, explained later, we have more general action
  • #16 * gmock takes care of the rest * checks for violation and outputs precise diagnostic messages * WILL MARK TEST AS FAILED * checks are done as soon as possible, so can drop into debugger at THAT MOMENT
  • #17 Mention the matcher library and custom matchers.
  • #18 * If called too many times, gmock will complain when amount is exceeded * if called too few times, gmock will complain when the mock is destroyed * Custom cardinalities possible but have never been requested
  • #19 Can define any acyclic dependency graph with it
  • #20 Type safe: performing incompatible operations on arguments or returning incompatible type will cause build error
  • #21 * More advanced API for developing matchers is available
  • #22 * First one will not compile if the method has less than 3 arguments * Can have even more advanced 
  • #24 * Imagine a client that tries an operation and has to repeat it after 2 seconds if it fails
  • #26 * Note: we never have defined actual socket class
  • #27 * Google Mock doctor