Это третья часть материала. Первая часть. Вторая часть.
Сегодня мы будет тестировать разработанный ранее бэкенд.
Цель тестирования
Цель тестирования — убедиться, что все функции приложения работают как положено. Мы проверим, что разработанный нами бэкенд возвращает корректные ответы пользователям. Мы знаем, что в конкретном случае должен ответить сервер, вот и проверим это.
Вспомним, какие методы API должны работать в приложении. На текущий момент у нас реализованы три конечные точки и две из них поддерживают два HTTP-метода:
- /currencies (GET, POST)
- /convert (POST)
- /webhook (POST, DELETE)
Итого, нам нужно сделать пять тестов, это не считая тестов загрузки приложения и т.п.
Методика тестирования
В Go есть встроенная утилита тестирования (go test), с её помощью писать и выполнять тесты очень удобно. Файлы, оканчивающиеся на _test.go будут автоматически включены в план тестирования, а функции тестирования имеют запись типа func(t *testing.T) и они будут выполнены в том же порядке, в каком написаны в файле. Имейте в виду, что файлы тестов не попадают в приложение при сборке.
План
Встроенная в Go подсистема тестирования требует небольшой инициализации. К счастью, в Go есть метод init(), всегда выполняющийся первым — даже при тестировании.
Вот пример инициализации:
var (
server *Server
runError error
)
func init() {
var err error
server, err = New()
if err != nil {
panic(err)
}
go func() {
runError = server.Run()
if runError != nil {
panic(runError)
}
}()
}
А теперь добавим несколько функций для проверки конечных точек API.
Тестирование инициализации
В нижеприведённом кусочке кода описана небольшая функция, проверяющая первичный запуск сервера и его непрерывную работу (в цикле, с помощью time.Sleep). При каждой итерации проверяется server.hasCurrencies для остановки цикла тестирования, когда сервер станет готов:
func TestServerCreation(t *testing.T) {
if server == nil {
t.Fatal("Server not initialized!")
}
if runError != nil {
t.Fatal("Error starting the server!")
}
for loops := 0; !server.hasCurrencies && loops < 10; loops++ {
t.Log("Sleep:", loops+1)
time.Sleep(time.Duration(500*(loops+1)) * time.Millisecond)
}
if !server.hasCurrencies {
t.Fatal("Currencies not loaded!")
}
}
Эта функция располагается в файле a_test.go. Выбор названия файла объясняется тем, что тесты запускают файлы в алфавитном порядке, поэтому называем их, начиная с "a".
Дальнейшее тестирование
Все тесты проводятся таким же способом, используя функционал go test.
Загрузите их себе из репозитория и проверьте сами.
Проверим вывод после прохода тестов:
➜ currencyconverter git:(master) go test -v -cover ./...
? github.com/goingfullstack/currencyconverter [no test files]
=== RUN TestServerCreation
2017/02/15 20 : 02 : 05 Starting server on 127.0.0.1:4000
2017/02/15 20 : 02 : 05 Starting currency fetching...
2017/02/15 20 : 02 : 05 Starting new currency fetch...
2017/02/15 20 : 02 : 05 Currencies updated.
2017/02/15 20 : 02 : 05 Sleeping 1h0m0s
--- PASS: TestServerCreation (0.50s)
a_test.go: 18 : Sleep: 1
=== RUN TestCurrencyConversionNewServer
--- PASS: TestCurrencyConversionNewServer (0.00s)
=== RUN TestCurrencyConversion
--- PASS: TestCurrencyConversion (0.00s)
=== RUN TestUnknownCurrency
--- PASS: TestUnknownCurrency (0.00s)
=== RUN TestConvertResponseCreation
--- PASS: TestConvertResponseCreation (0.00s)
=== RUN TestConvertedResponseUnknownCurrency
--- PASS: TestConvertedResponseUnknownCurrency (0.00s)
=== RUN TestCreateCurrencyResponse
--- PASS: TestCreateCurrencyResponse (0.00s)
=== RUN TestCreateInvalidCurrencyResponse
--- PASS: TestCreateInvalidCurrencyResponse (0.00s)
=== RUN TestCurrencyGet
2017/02/15 20 : 02 : 05 [GET] /currencies
--- PASS: TestCurrencyGet (0.00s)
=== RUN TestCurrencyPostKnownCurrency
2017/02/15 20 : 02 : 05 [POST] /currencies
--- PASS: TestCurrencyPostKnownCurrency (0.00s)
=== RUN TestCurrencyPostInvalidRequest
2017/02/15 20 : 02 : 05 [POST] /currencies
2017/02/15 20 : 02 : 05 EOF
--- PASS: TestCurrencyPostInvalidRequest (0.00s)
=== RUN TestCurrencyPostUnknownCurrency
2017/02/15 20 : 02 : 05 [POST] /currencies
2017/02/15 20 : 02 : 05 Unknown currency: FOO
--- PASS: TestCurrencyPostUnknownCurrency (0.00s)
=== RUN TestCurrencyPut
2017/02/15 20 : 02 : 05 [PUT] /currencies
--- PASS: TestCurrencyPut (0.00s)
=== RUN TestConvert
2017/02/15 20 : 02 : 05 [POST] /convert
--- PASS: TestConvert (0.00s)
=== RUN TestConvertInvalidMethod
2017/02/15 20 : 02 : 05 [PUT] /convert
--- PASS: TestConvertInvalidMethod (0.00s)
=== RUN TestConvertInvalidCurrency
2017/02/15 20 : 02 : 05 [POST] /convert
2017/02/15 20 : 02 : 05 Unknown currency: INVALID
--- PASS: TestConvertInvalidCurrency (0.00s)
=== RUN TestConvertInvalidRequestData
2017/02/15 20 : 02 : 05 [POST] /convert
2017/02/15 20 : 02 : 05 EOF
--- PASS: TestConvertInvalidRequestData (0.00s)
=== RUN TestNotFoundRoute
2017/02/15 20 : 02 : 05 [GET] /notfound
--- PASS: TestNotFoundRoute (0.00s)
=== RUN TestWebhookRegister
2017/02/15 20 : 02 : 05 [POST] /webhook
2017/02/15 20 : 02 : 05 Webhook return code: 200
--- PASS: TestWebhookRegister (0.00s)
=== RUN TestWebhookCalling
2017/02/15 20 : 02 : 05 Webhook return code: 200
--- PASS: TestWebhookCalling (0.00s)
=== RUN TestWebhookWrongSecret
2017/02/15 20 : 02 : 05 [POST] /webhook
2017/02/15 20 : 02 : 05 Webhook return code: 403
--- PASS: TestWebhookWrongSecret (0.00s)
=== RUN TestWebhookWrongBase
2017/02/15 20 : 02 : 05 [POST] /webhook
--- PASS: TestWebhookWrongBase (0.00s)
=== RUN TestWebhookGet
2017/02/15 20 : 02 : 05 [GET] /webhook
--- PASS: TestWebhookGet (0.00s)
PASS
coverage: 85.1{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} of statements
ok github.com/goingfullstack/currencyconverter/server 0.524s coverage: 85.1{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} of statements
Как видно из последней строки, тест покрыл 85,1{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} нашего кода - можно сделать ещё лучше, но пока этого достаточно.
В следующей части мы настроим бэкенд для реальной работы, а тесты, написанные сегодня, будут использованы когда мы автоматизируем процесс компиляции и установки на сервер - но это немного позже.
Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.
Пишите: @ighar. Buy me a coffee, please :).