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

27
Модульное тестирование и Google Mock Владимир Лосев Google [email protected] Yet Another Conference 2011 Москва, 19 сентября 1

Upload: yaevents

Post on 17-Jan-2015

12.336 views

Category:

Technology


2 download

DESCRIPTION

Владимир Лосев, GoogleЗакончил математико-механический факультет Санкт-Петербургского государственного университета в 1995 году. Работал в компаниях Motоrola, Fair Isaac и Yahoo. С 2008 года работает в Google, в группе, занимающейся вопросами повышения производительности инженеров.Тема докладаЮнит-тестирование и Google Mock.ТезисыВ модульных (юнит) тестах каждый элемент программы тестируется по отдельности, в изоляции от других. Такие тесты исполняются очень быстро, поэтому их можно запускать когда угодно, что позволяет отлавливать дефекты на самых ранних стадиях разработки. Однако для тестирования объекта в изоляции от других необходимо имитировать поведение связанных с ним объектов, что на C++ довольно утомительное занятие. Разработанная в Googlе библиотека для создания и использования mock-объектов — Google Mock — позволяет существенно упростить этот процесс и ускорить написание тестов. В докладе пойдет речь о принципах и возможностях библиотеки, примерах её использования и её внутреннем устройстве.

TRANSCRIPT

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

 Модульное тестирование и Google Mock

Владимир ЛосевGoogle

[email protected]

Yet Another Conference 2011Москва, 19 сентября

1

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

Agenda

1. Почему Google Mock?2. Как им пользоваться3. Примеры

2

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

Хочешь жить без багов?Спроси меня как!

• Ошибки снижают производительность• ...Если не чинить их быстро• Нужны автоматизированные тесты

o Быстрыеo Надёжныеo Точные

• Тестируем по одному модулю за раз

3

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

Изоляция модулей

• В программах на C++ абстрагируем взаимодействия между объектами через интерфейсы

• Используем тестовые двойники (stub-, mock-объекты, и т.д.) для имитации поведения соседей

• Используем метод внедрения зависимостей для добавления двойников

4

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

Внедрение зависимостей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

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

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

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

Тест с таким объектом

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

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

Google Mock• Google C++ Mocking Framework/Google Mock/gMock• Написан в 2007 г. Жаньонгом Ваном (Zhanyong Wan)• Код открыт в 2008 г.• Лежит на code.google.com/p/googlemock• Используется во многих проектах с открытым кодом

(Chromium, LLVM)

8

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

Нужна библиотека для написания тестов

• Хорошо интегрирован с Google Test• Лежит на http://code.google.com/p/googletest• Позволяет легко и быстро писать тесты:

  #include <gtest/gtest.h>

  TEST(MathTest, ArithmeticsStillWorks) {    EXPECT_EQ(4, 2 * 2);  }

9

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

Mock-объект на Google Mock class MockSocket : public SocketInterface { public:  MOCK_METHOD2(Read, int(void* buffer, int n));};

10

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

Определение ожиданий class MockSocket : public SocketInterface { public:  MOCK_METHOD2(Read, int(void* buffer, int n));};

  EXPECT_CALL(mock_socket, Read(…))

11

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

Описние параметровclass MockSocket : public SocketInterface { public:  MOCK_METHOD2(Read, int(void* buffer, int n));};

  EXPECT_CALL(mock_socket, Read(_, Ge(25)))

12

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

Описание количества вызовов class MockSocket : public SocketInterface { public:  MOCK_METHOD2(Read, int(void* buffer, int n));};

  EXPECT_CALL(mock_socket, Read(_, Ge(25)))      .Times(2)

13

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

Описание поведенияclass MockSocket : public SocketInterface { public:  MOCK_METHOD2(Read, int(void* buffer, int n));};

  string data("1234567890123456789012345");  EXPECT_CALL(mock_socket, Read(_, Ge(25)))      .Times(2)      .WillOnce(DoAll(CopyData(data),                      Return(data.size())))      .WillOnce(Return(0));

14

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

Полный тестclass MockSocket : public SocketInterface { public:  MOCK_METHOD2(Read, int(void* buffer, int n));};

TEST(Server_ReadRequest, ReadsCompleteRequest) {  MockSocket mock_socket;  string data("1234567890123456789012345");  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

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

Предикаты• ...на стероидах

o Проверяют условияo Описывают эти условияo Предоставляют объяснения

Примеры:

Простые: 42, _, Gt(32), NotNull()Составные: AllOf(m1, ...), AnyOf(m1, ...), Not(matcher)Для контейнеров: Contains(matcher), Each(matcher)ElementsAre(e1, ..., en), ElementsAreArray(arr)

• Можно определять собственные

16

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

Количество вызовов

• Указывается в методе Times():

  EXPECT_CALL(mock, Foo()).Times(cardinality);

• Можно указывать:o 2o Exactly(2)o AtLeast(3)o AtMost(5)o Between(3, 4)

17

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

Порядок

• По умолчанию порядок вызовов не задаётся• Можно указывать полный или частичный порядок• Отсутствие циклов гаранировано

{  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

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

Действия

• Определяются в методах 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

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

Расширяем Google Mock – предикаты

MATCHER(IsEven, "") { return arg % 2 == 0; }

MATCHER_P(IsDivisibleBy, n, "") {  return arg % n == 0;}

MATCHER_P2(IsSumOf, a, b, "") {  return arg == a + b;}EXPECT_CALL(mock, Foo(IsSumOf(x, 7)));

• Не должны вызывать сторонних эффектов• Не должны содержать изменяемого состояния• Есть более продвинутое API для создания предикатов

20

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

Расширяем 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

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

Пример: внедрение ошибок

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

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

Пример: быстрый сон

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

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

Пример: быстрый сон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

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

Преимущества

• Проверяет взаимодействие между объектом и соседями• Позволяет писать быстрые тесты• Позволяет писать надёжные тесты• Упрощает тестирование кода обработки ошибок• Позволяет писать код, не имея соседей

25

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

Недостатки

• Mock-объекты компилируются медленно• Малопонятная диагностика

o Написан Google Mock Doctor, скрипт для интерпретации диагностики (GCC и LLVM)

• Mock-нужно писать вручнуюo Есть скрипт для генерации mock-классов из

определений интерфейсов или классов

26

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

Google Mock

http://code.google.com/p/googlemock

http://code.google.com/p/googlemock/wiki/Documentation

[email protected] (English)

27