Как тестируют в Google - Страница 17

Изменить размер шрифта:

На функцию 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.

 // Clients set using set_* methods above.

 int error_code_;

 string error_details_;

};

// The test fixture for AddUrlFrontend. It is code shared by the

// TEST_F test definitions below. For every test using this

// fixture, the fixture will create a FakeAddUrlService, an

// AddUrlFrontend, and inject the FakeAddUrlService into that

// AddUrlFrontend. Tests will have access to both of these

// objects at runtime.

class AddurlFrontendTest : public ::testing::Test {

// Runs before every test method is executed.

 virtual void SetUp() {

// Create a FakeAddUrlService for  injection.

fake_add_url_service_.reset(new FakeAddUrlService);

// Create an AddUrlFrontend and inject our FakeAddUrlService

// into it.

add_url_frontend_.reset(

new AddUrlFrontend(fake_add_url_service_.get()));

}

 scoped_ptr fake_add_url_service_;

 scoped_ptr add_url_frontend_;

};

// Test that AddurlFrontendTest::SetUp works.

TEST_F(AddurlFrontendTest, FixtureTest) {

 // AddurlFrontendTest::SetUp was invoked by this  point.

}

// Test that AddUrlFrontend parses URLs correctly from its

// query parameters.

TEST_F(AddurlFrontendTest, ParsesUrlCorrectly) {

 HTTPRequest http_request;

 HTTPReply http_reply;

 // Configure the request to go to the /addurl resource and

 // to contain a 'url' query parameter.

 http_request.set_text(

"GET /addurl?url=http://www.foo.com HTTP/1.1");

 // Tell the FakeAddUrlService to expect to receive a URL

 // of 'http://www.foo.com'.

 fake_add_url_service_->set_expected_url("http://www.foo.com");

 // Send the request to AddUrlFrontend, which should dispatch

 // a request to the FakeAddUrlService.

 add_url_frontend_->HandleAddUrlFrontendRequest(

&http_request, &http_reply);

 // Validate the response.

 EXPECT_STREQ("200 OK", http_reply.text());

}

// Test that AddUrlFrontend parses comments correctly from its

// query parameters.

TEST_F(AddurlFrontendTest, ParsesCommentCorrectly) {

 HTTPRequest http_request;

 HTTPReply http_reply;

 // Configure the request to go to the /addurl resource and

 // to contain a 'url' query parameter and to also contain

// a 'comment' query parameter that contains the

 // url-encoded query string 'Test comment'.

 http_request.set_text("GET /addurl?url=http://www.foo.com"

"&comment=Test+comment HTTP/1.1");

 // Tell the FakeAddUrlService to expect to receive a URL

 // of 'http://www.foo.com' again.

 fake_add_url_service_->set_expected_url("http://www.foo.com");

 // Tell the FakeAddUrlService to also expect to receive a

 // comment of 'Test comment' this  time.

 fake_add_url_service_->set_expected_comment("Test comment");

Оригинальный текст книги читать онлайн бесплатно в онлайн-библиотеке Knigger.com