Шпаргалка по инструменту тестирования API каратэ

Karate - это инструмент тестирования API с открытым исходным кодом, разработанный Питер Томас из Intuit. Karate построен на основе HttpClient и Cucumber и имеет собственный DSL, чтобы упростить тестирование API. Несмотря на то, что он существует уже почти год, он очень быстро развился и обладает всеми возможностями, ожидаемыми от инструмента тестирования API.

Поскольку каратэ находится поверх огурца, оно наследует все функции огурца, поэтому вы можете писать тесты API в простом формате Given When Then и использовать все ключевые слова огурца, такие как Feature, Scenario Outline, Scenario, Примеры, Feature tagging.

Я создал эту шпаргалку, чтобы помочь всем, кто участвует в тестировании API, с примерами использования инструмента карате.

Пожалуйста, обрати внимание , эта шпаргалка - лишь верхушка айсберга. Каратэ имеет много других особенностей, которые здесь не упоминаются. Этот список - всего лишь наиболее распространенные операции, которые обычно используются при тестировании API.

Добавьте зависимости (pom.xml)


UTF-8
3.7.0
1.8
1.8
1.8
0.8.0.RC4
3.13.0


com.intuit.karate
karate-core
${karate.version}


com.intuit.karate
karate-apache
${karate.version}
test


com.intuit.karate
karate-testng
${karate.version}


net.masterthought
cucumber-reporting
${cucumber.reporting.version}
test

Структура проекта

Вы можете организовать и структурировать свой проект maven следующим образом:



каратэ-config.js

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

function() {
var env = karate.env; // get java system property 'karate.env'
karate.log('karate.env selected environment was:', env);
karate.configure('ssl', true)
if (!env) {
env = 'dev'; //env can be anything: dev, qa, staging, etc.
}
var config = {
env: env,
AM_USERNAME: 'devuser',
AM_PASSWORD: 'devpass',
AM_HOST: 'https://am.'+env+'.example.net',
AM_AUTHENTICATE_PATH: '/am/json/realms/root/authenticate',
IDM_USERNAME: 'devuser',
IDM_PASSWORD: 'devpass',
IDM_HOST: 'https://idm.'+env+'.example.net',
IDM_MANAGED_USER_PATH: '/idm/managed/user',
};
if(env == 'qa') {
config.AM_USERNAME: 'myUserName'
config.AM_PASSWORD: 'myPa55word'
}
if(env == 'live') {
config.AM_USERNAME: 'admin'
config.AM_PASSWORD: 'secret'
}
karate.log('OpenAM Host:', config.AM_HOST);
karate.configure('connectTimeout', 60000);
karate.configure('readTimeout', 60000);
return config; }

Как отправить HTTP-запрос (Get, Post, Put, Delete, Patch)

@FR Feature: AM Admin Login
Scenario: Login as Admin to AM and get token
Given header X-OpenAM-Username = AM_USERNAME
Given header X-OpenAM-Password = AM_PASSWORD
Given url AM_HOST + AM_AUTHENTICATE_PATH
And request ''
When method POST
Then status 200
* assert response.tokenId != null
* def tokenId = response.tokenId

В приведенном выше примере AM_USERNAME, AM_PASSWORD, AM_HOST и AM_AUTHENTICATE_PATH берутся из karate-config.js файл.

' 'Можно интерпретировать как любое из 'Дано', 'Когда', 'Тогда', 'И', но когда действие не обслуживает контекст, мы можем использовать ' '.

’+’ Действует как оператор конкатенации

В приведенном выше примере отправляется пустой запрос тела сообщения. Мы можем просто использовать ‘‘

Метод может быть любым допустимым HTTP-глаголом (Get, Post, Put, Patch, Delete).

' def ’Используется для хранения значения в переменной.

заголовок , url , запрос , метод , статус , отклик все ключевые слова карате образуют DSL. Чтобы увидеть полный список ключевых слов, посетите Intuit.

В приведенном выше примере ответ имеет формат JSON, поэтому мы можем использовать встроенную в карате нотацию JsonPath для анализа ответа.

Цепочка запросов с несколькими вызовами API

Feature: request chaining with multiple api calls Scenario: chain request demo
* json req = read('classpath:com/example/templates/idm/create-user-template.json')
* def user = req.givenName
Given header X-Username = 'anonymous'
Given header X-Password = 'anonymous'
Given url AM_HOST + '/some/endpoint
And request ''
When method POST
* def authId = response.authId
* def payload1 =
'''
{'authId':'${authId}','callbacks':[{'type':'NameCallback','output':[{'name':'prompt','value':'Email Address'}],'input':[{'name':'IDToken0','value':'${user}@putsbox.com'}]}]}
'''
* replace payload1
| token
| value |
| ${authId} | authId |
| ${user} | user |
* json mypayload1 = payload1
Given header X-Username = 'anonymous'
Given header X-Password = 'anonymous'
Given url AM_HOST + '/openam/some-other-endpoint
And request mypayload1
When method POST

В приведенном выше примере выполняется первый вызов, и authId анализируется из ответа и сохраняется в переменной authId. Затем мы заменяем вторую полезную нагрузку на authId, полученный при первом вызове. Затем мы используем новую полезную нагрузку для отправки следующему вызову API.

Как читать шаблоны запросов и вызывать другие файлы функций

Мы можем сделать наши сценарии повторно используемыми и вызывать их из других файлов функций. В этом примере мы можем создать «общий» файл create-user.feature, в котором мы можем отправить запрос на создание пользователя, но с другим телом запроса.

Feature: Create User in IDM
Scenario: Create user in IDM with given guid
Given header X-Requested-With = 'Swagger-UI'
Given header X-OpenIDM-Username = IDM_USERNAME
Given header X-OpenIDM-Password = IDM_PASSWORD
Given url IDM_HOST + IDM_MANAGED_USER_PATH
And request __arg
When method POST
Then status 201

Обратите внимание, что в приведенном выше примере мы используем __arg в качестве запроса тела сообщения.

Затем мы можем вызвать указанный выше файл функций и передать требуемое тело сообщения, которое, в свою очередь, мы можем прочитать из шаблона.

Feature: Create a user
Scenario: Create user in IDM
* json myReq = read('classpath:com/example/templates/idm/idm-create-user-template.json')
* call read('classpath:com/example/idm/idm-create-user.feature') myReq

Приведенный выше код считывает шаблон, который находится в расположении com/example/templates/idm/idm-create-user-template.json и сохраняет его как переменную JSON с именем myReq

Затем мы можем отправить переменную JSON в другой файл функции, используя метод call.

Шаблон выглядит как

{
'mail' : 'david@putsbox.com',
'givenName' : 'david',
'sn' : 'putsbox',
'jobRole' : 'developer',
'telephoneNumber' : '91234567890',
'dob' : '01/02/2010', }

Как читать другие файлы функций - пример 2

Мы можем прочитать конкретную переменную в вызываемом файле функций, который передается из вызывающего файла функций.

Feature: Create User in IDM
Scenario: Create user in IDM with given guid
Given header X-Requested-With = 'Swagger-UI'
Given header X-OpenIDM-Username = IDM_USERNAME
Given header X-OpenIDM-Password = IDM_PASSWORD
Given url IDM_HOST + IDM_MANAGED_USER_PATH
And request __arg.emailAddress
When method POST
Then status 201

Обратите внимание: в приведенном выше примере мы используем __arg.emailAddress в качестве запроса тела сообщения. Нас интересует только отправка адреса электронной почты в качестве запроса

Затем мы можем вызвать указанный выше файл функций и передать требуемое тело сообщения, которое, в свою очередь, мы можем прочитать из шаблона.

Feature: Create a user
Scenario: Create user in IDM
* json myReq = read('classpath:com/example/templates/idm/idm-create-user-template.json')
* json emailAddress = '{'emailAddress': '' +myReq.mail+ ''}'
* call read('classpath:com/example/fr/idm/idm-create-user.feature') emailAddress

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

Затем мы можем отправить переменную JSON в другой файл функции с помощью метода call и отправить переменную JSON, в данном случае emailAddress.

Создайте класс Test Runner

Мы можем выполнять сценарии в файле функций с помощью maven (что полезно для запуска тестов в среде CI)

import com.intuit.karate.cucumber.CucumberRunner; import com.intuit.karate.cucumber.KarateStats; import cucumber.api.CucumberOptions; import net.masterthought.cucumber.Configuration; import net.masterthought.cucumber.ReportBuilder; import org.apache.commons.io.FileUtils; import org.testng.annotations.Test; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; import static org.testng.AssertJUnit.assertTrue; @CucumberOptions(tags = {'@FR', '~@ignore'}) public class TestRunner_FR {
@Test
public void testParallel() {
String karateOutputPath = 'target/cucumber-html-reports';
KarateStats stats = CucumberRunner.parallel(getClass(), 1, karateOutputPath);
generateReport(karateOutputPath);
assertTrue('there are scenario failures', stats.getFailCount() == 0);
}
private static void generateReport(String karateOutputPath) {
Collection jsonFiles = FileUtils.listFiles(new File(karateOutputPath), new String[] {'json'}, true);
List jsonPaths = new ArrayList(jsonFiles.size());
for (File file : jsonFiles) {

jsonPaths.add(file.getAbsolutePath());
}
Configuration config = new Configuration(new File('target'), 'YOUR PROJECT NAME');
config.addClassifications('Environment', System.getProperty('karate.env'));
ReportBuilder reportBuilder = new ReportBuilder(jsonPaths, config);
reportBuilder.generateReports();
} }

Приведенный выше код запускает все файлы функций, помеченные как «@FR», но игнорирует все тесты, помеченные как «@ignore».

Он также создает отчет по огурцу для визуализации результатов тестовых прогонов.

Запустите тесты из командной строки или CI

mvn clean test -DargLine='-Dkarate.env=staging' -Dtest=TestRunner_FR

Здесь мы запускаем класс TestRunner_FR и устанавливаем среду как промежуточную.

Выполнить JavaScript в файле функции

В файле функций у нас также есть возможность выполнять javascript

Feature: Generate a random session id
Scenario: generate random session id
* def random_string =
'''
function(s) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
for (var i = 0; i < s; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
'''
* def sessionId = random_string(10)

Приведенный выше код генерирует случайную строку длиной 10 и сохраняет ее в переменной с именем sessionId.

Тесты на основе данных

Поскольку каратэ находится на вершине огурца, тестирование на основе данных по умолчанию.

Feature: Data driven testing example Scenario Outline: An 'Invalid input request' error is returned if required parameters have incorrect values.
* def attribute_name = ''
* xml malformed_request =
* json activate_request = malformed_request
* def activate_response = call read('activate.feature') activate_request
* match activate_response.contentType == 'text/xml;charset=ISO-8859-1'
* match activate_response.gas_version == '5.2.7'
* match activate_response.error_code == '1000'
Examples:
| name_attribute | method_call













|
| auth_method
| Java.type('com.example.StringUtil').removeNodeByAttribute(xml_req, attribute_name) |
| app_url
| Java.type('com.example.StringUtil').removeNodeByAttribute(xml_req, attribute_name) |

В приведенном выше примере используются ключевые слова «Схема сценария» и «Примеры» Cucumber для создания тестов на основе данных. Для чтения каждого параметра мы используем угловые скобки

Вызов Java из файла функций

package com.example; public class StringUtil {
public static String getNumberFromString(String text) {
return text.replaceAll('\D+', '');
} }
Feature: Call java demo Scenario: Get number from text
Given url 'https://preview.putsbox.com/p/david/last.json'
When method GET
* def emailText = response.text
* def otpCode = Java.type('com.example.StringUtil').getNumberFromString(emailText)
* print otpCode

Приведенный выше файл функций вызывает метод Java в классе с именем StringUtil. Затем сохраняет ответ на этот вызов в переменную otpCode.