`
Читать книги » Книги » Компьютеры и Интернет » Программирование » Джеймс Уиттакер - Как тестируют в Google

Джеймс Уиттакер - Как тестируют в Google

1 ... 13 14 15 16 17 ... 76 ВПЕРЕД
Перейти на страницу:

Плюсы того, что большинство сотрудников используют один набор инструментов и единую инфраструктуру, трудно переоценить. Одной простой командой инженер может собрать и исполнить все бинарники и тесты, которые связаны с его списком изменений, получить данные о покрытии кода, сохранить и проанализировать результаты в облаке, а потом посмотреть их в виде отчета на постоянной веб-странице. Результат выводится в терминал в виде сообщения «PASS» или «FAIL» со ссылками на подробную информацию. Когда разработчик выполняет тесты, их результаты и данные о покрытии кода сохраняются в облаке, и любой рецензент может посмотреть их через внутренний инструмент для код-ревью.

Пример работы разработчика в тестировании

Следующий пример объединяет все, о чем мы говорили выше. Предупреждаем, в этом разделе много технической информации с уймой низкоуровневых деталей. Если вам интересна только общая картина, смело переходите к следующему разделу.

Представьте простое веб-приложение, с помощью которого пользователи отправляют URL-адреса в Google для добавления в Google-индекс. Форма HTML содержит два поля — ULR-адрес и комментарий — и генерирует запрос HTTP GET к серверу Google в следующем формате:

GET /addurl?url=http://www.foo.com&comment=Foo+comment HTTP/1.1

На стороне сервера это веб-приложение делится на две части: AddUrlFrontend, который получает запрос HTTP, распознает и проверяет его, и бэкенд AddUrlService. Сервис бэкенда получает запросы от AddUrlFrontend, проверяет, нет ли в них ошибок, и дальше взаимодействует с такими хранилищами данных, как, например, Google Bigtable[22] или Google File System.[23]

Разработчик начинает работу с создания каталога для проекта:

$  mkdir  depot/addurl/

Затем он определяет протокол AddUrlService с использованием языка Protocol Buffers:[24]

File: depot/addurl/addurl.proto

message AddUrlRequest  {

   required  string  url  =  1;            //  The  URL  address  entered  by  user.

   optional  string  comment  =  2;    //  Comments  made  by  user.

}

message  AddUrlReply  {

   //  Error  code  if  an  error  occured.

   optional  int32  error_code  =  1;

   //  Error  mtssage  if  an  error  occured.  

optional  string  error_details  =  2;

}

service  AddUrlService  {

   //  Accepts  a  URL  for  submission  to  the  index.

   rpc  AddUrl(AddUrlRequest)  returns  (AddUrlReply)  {

       option  deadline  =  10.0;

   }

}

В файле addurl.proto определены три важных элемента: сообщения AddUrl­Request и AddUrlReply и сервис удаленного вызова процедур (RPC, Remote Procedure) AddUrlService.

Посмотрев на определения сообщения AddUrlRequest, мы видим, что поле url должно быть задано вызывающей стороной, а поле comment не является обязательным.

Точно так же из определения сообщения AddUrlReply следует, что оба поля — error_code и error_details опционально могут быть переданы в ответах сервиса. Мы предполагаем, что в типичном случае, когда URL-адрес успешно принят, эти поля останутся пустыми, чтобы минимизировать объем передаваемых данных. Это одно из правил Google: типичный случай должен работать быстро.

Из определения AddUrlService видно, что сервис содержит единственный метод AddUrl, который принимает AddUrlRequest и возвращает AddUrlReply. По умолчанию вызов метода AddUrl прерывается по тайм-ауту через 10 секунд, если клиент не получил ответа за это время. Реализации интерфейса AddUrlService могут включать в себя сколько угодно систем хранения данных, но для клиентов интерфейса это несущественно, поэтому эти подробности не отражены в файле addurl.proto.

Обозначение '= 1' в полях сообщений не имеет никакого отношения к значениям этих полей. Оно существует для того, чтобы протокол можно было дорабатывать. Например, кто-то захочет добавить поле uri в сообщение AddUrlRequest к уже имеющимся полям. Для этого вносится следующее изменение:

message  AddUrlRequest  {

   required  string  url  =  1;            //  The  URL  entered  by  the  user.

   optional  string  comment  =  2;    //  Comments  made  by  the  user.

   optional  string  uri  =  3;            //  The  URI  entered  by  the  user.

}

Но это выглядит довольно глупо — скорее всего, потребуется просто переименовать поле url в uri. Если это число и тип останутся неизменными, сохранится совместимость между старой и новой версией:

message  AddUrlRequest  {

   required  string  uri  =  1;            //  The  URI  entered  by  user.

   optional  string  comment  =  2;    //  Comments  made  by  the  user.

}

Написав файл addurl.proto, разработчик переходит к созданию правила сборки proto_library, которое генерирует исходные файлы C++, определяющие сущности из addurl.proto, и компилирует их в статическую библиотеку addurl C++. С дополнительными параметрами можно сгенерировать исходный код для языков Java и Python.

File: depot/addurl/BUILD

proto_library(name="addurl",

                           srcs=["addurl.proto"])

Разработчик запускает систему сборки и исправляет все проблемы, обнаруженные ею в addurl.proto и в файле BUILD. Система сборки вызывает компилятор Protocol Buffers, генерирует исходные файлы addurl.pb.h и addurl.pb.cc и статическую библиотеку addurl, которую теперь можно подключить.

Пора писать AddUrlFrontend. Для этого мы объявляем класс AddUrlFrontend в новом файле addurl_frontend.h. Этот код в основном шаблонный.

File: depot/addurl/addurl_frontend.h

#ifndef  ADDURL_ADDURL_FRONTEND_H_

#define  ADDURL_ADDURL_FRONTEND_H_

//  Forward-declaration  of  dependencies.

class  AddUrlService;

class  HTTPRequest;

class  HTTPReply;

//  Frontend  for  the  AddUrl  system.

//  Accepts  HTTP  requests  from  web  clients,

//  and  forwards  well-formed  requests  to  the  backend.

class  AddUrlFrontend  {

   public:

           //  Constructor  which  enables  injection  of  an

           //  AddUrlService  dependency.

       explicit  AddUrlFrontend(AddUrlService*  add_url_service);

       ~AddUrlFrontend();

       //  Method  invoked  by  our  HTTP  server  when  a  request  arrives

       //  for  the  /addurl  resource.

       void  HandleAddUrlFrontendRequest(const  HTTPRequest*  http_request,

                                                                         HTTPReply*  http_reply);

   private:

       AddUrlService*  add_url_service_;

       //  Declare  copy  constructor  and  operator=  private  to  prohibit

       //  unintentional  copying  of  instances  of  this  class.

       AddUrlFrontend(const  AddUrlFrontend&);

       AddUrlFrontend&  operator=(const  AddUrlFrontend&  rhs);

   };

#endif  //  ADDURL_ADDURL_FRONTEND_H_

Продолжая определять классы AddUrlFrontend, разработчик создает файл addurl_frontend.cc, в котором описывает класс AddUrlFrontend. Для экономии места мы опустили часть файла.

File: depot/addurl/addurl_frontend.cc

#include  "addurl/addurl_frontend.h"

#include  "addurl/addurl.pb.h"

#include  "path/to/httpqueryparams.h"

//  Functions  used  by  HandleAddUrlFrontendRequest()  below,  but

//  whose  definitions  are  omitted  for  brevity.

void  ExtractHttpQueryParams(const  HTTPRequest*  http_request,

                                                       HTTPQueryParams*  query_params);

void  WriteHttp200Reply(HTTPReply*  reply);

void  WriteHttpReplyWithErrorDetails(

       HTTPReply*  http_reply,  const  AddUrlReply&  add_url_reply);

//  AddUrlFrontend  constructor  that  injects  the  AddUrlService

//  dependency.

AddUrlFrontend::AddUrlFrontend(AddUrlService*  add_url_service)

       :  add_url_service_(add_url_service)  {

}

//  AddUrlFrontend  destructor–there's  nothing  to  do  here.

AddUrlFrontend::~AddUrlFrontend()  {

}

//  HandleAddUrlFrontendRequest:

//  Handles  requests  to  /addurl  by  parsing  the  request,

//  dispatching  a  backend  request  to  an  AddUrlService  backend,

//  and  transforming  the  backend  reply  into  an  appropriate

//  HTTP  reply.

//

//  Args:

//    http_request–The  raw  HTTP  request  received  by  the  server.

//    http_reply–The  raw  HTTP  reply  to  send  in  response.

void  AddUrlFrontend::HandleAddUrlFrontendRequest(

       const  HTTPRequest*  http_request,  HTTPReply*  http_reply)  {

   //  Extract  the  query  parameters  from  the  raw  HTTP  request.

   HTTPQueryParams  query_params;

   ExtractHttpQueryParams(http_request,  &query_params);

   //  Get  the  'url'  and  'comment'  query  components.

   //  Default  each  to  an  empty  string  if  they  were  not  present

   //  in  http_request.

   string  url  =

query_params.GetQueryComponentDefault("url",  "");

string  comment  =

       query_params.GetQueryComponentDefault("comment",  "");

//  Prepare  the  request  to  the  AddUrlService  backend.

AddUrlRequest  add_url_request;

AddUrlReply  add_url_reply;

add_url_request.set_url(url);

if  (!comment.empty())  {

   add_url_request.set_comment(comment);

}

//  Issue  the  request  to  the  AddUrlService  backend.

RPC  rpc;

add_url_service_->AddUrl(

       &rpc,  &add_url_request,  &add_url_reply);

//  Block  until  the  reply  is  received  from  the

//  AddUrlService  backend.

rpc.Wait();

//  Handle  errors,  if  any:

if  (add_url_reply.has_error_code())  {

   WriteHttpReplyWithErrorDetails(http_reply,  add_url_reply);

}  else  {

   //  No  errors.  Send  HTTP  200  OK  response  to  client.

   WriteHttp200Reply(http_reply);

}

}

На функцию HandleAddUrlFrontendRequest ложится большая нагрузка — так устроены многие веб-обработчики. Разработчик может разгрузить эту функцию, выделив часть ее функциональности вспомогательным функциям. Но такой рефакторинг обычно не проводят, пока сборка не станет стабильной, а написанные юнит-тесты не будут успешно проходить.

1 ... 13 14 15 16 17 ... 76 ВПЕРЕД
Перейти на страницу:

Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Джеймс Уиттакер - Как тестируют в Google, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

Комментарии (0)