Джефф Каролло

Как тестируют в Google


Скачать книгу

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 ложится большая нагрузка – так устроены многие веб-обработчики. Разработчик может разгрузить эту функцию, выделив часть ее функциональности вспомогательным функциям. Но такой рефакторинг обычно не проводят, пока сборка не станет стабильной, а написанные юнит-тесты не будут успешно проходить.

      В этом месте разработчик изменяет существующую спецификацию сборки проекта addurl, включая в нее запись для библиотеки addurl_frontend. При сборке создается статическая библиотека C++ для AddUrlFrontend.

      File: /depot/addurl/BUILD

      # From before:

      proto_library(name="addurl",

       srcs=["addurl.proto"])

      # New:

      cc_library(name="addurl_frontend",

       srcs=["addurl_frontend.cc"],

       deps=[

       "path/to/httpqueryparams",

       "other_http_server_stuff",

       ":addurl", # Link against the addurl library above.

       ])

      Разработчик снова запускает средства сборки, исправляет ошибки компиляции и компоновщика в addurl_frontend.h и addurl_frontend.cc, пока все не будет собираться и компоноваться без предупреждений или ошибок. На этой стадии пора писать юнит-тесты для AddUrlFrontend. Они пишутся в новом файле addurl_frontend_test.cc. Тест определяет имитацию для бэкенд-системы AddUrlService и использует конструктор AddUrlFrontend для внедрения этой имитации во время тестирования. При таком подходе разработчик может внедрять ожидания и ошибки в поток операций AddUrlFrontend без изменения кода AddUrlFrontend.

      File: depot/addurl/addurl_frontend_test.cc

      #include "addurl/addurl.pb.h"

      #include "addurl/addurl_frontend.h"

      // See http://code.google.com/p/googletest/

      #include "path/to/googletest.h"

      // Defines a fake AddUrlService, which will be injected by

      // the AddUrlFrontendTest test fixture into AddUrlFrontend

      // instances under test.

      class FakeAddUrlService : public AddUrlService {

      public:

       FakeAddUrlService()

       : has_request_expectations_(false),

       error_code_(0) {

      }

      // Allows tests to set expectations on requests.

      void set_expected_url(const string& url) {

       expected_url_ = url;

       has_request_expectations_ = true;

      }

      void set_expected_comment(const string& comment) {

       expected_comment_ = comment;

       has_request_expectations_ = true;

      }

      // Allows for  injection of errors by tests.

      void set_error_code(int error_code) {

       error_code_ = error_code;

      }

      void set_error_details(const string& error_details) {

       error_details_ = error_details;

      }

      // Overrides of the AddUrlService::AddUrl method generated from

      // service definition in addurl.proto by the Protocol Buffer

      // compiler.

      virtual void AddUrl(RPC* rpc,

       const AddUrlRequest* request,

       AddUrlReply* reply) {

       // Enforce expectations on request (if present).

       if (has_request_expectations_) {

       EXPECT_EQ(expected_url_, request->url());

       EXPECT_EQ(expected_comment_, request->comment());

       }

       // Inject errors specified in the set_* methods above if present.

       if (error_code_ != 0 || !error_details_.empty()) {

       reply->set_error_code(error_code_);

       reply->set_error_details(error_details_);

       }

      }

      private:

       // Expected request information.

       // Clients set using set_expected_* methods.

       string expected_url_;

       string expected_comment_;

       bool has_request_expectations_;

       // Injected error information.

       //