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

Karate - гэта інструмент тэсціравання API з адкрытым кодам, распрацаваны Пітэр Томас з Intuit. Каратэ пабудавана на HttpClient і Cucumber і мае ўласную DSL, каб зрабіць тэставанне API вельмі простым. Хоць ён існуе амаль год, ён саспеў вельмі хутка і мае ўсе магчымасці, якія чакае інструмент тэставання API.

Паколькі каратэ сядзіць над агурком, ён успадкоўвае ўсе функцыянальныя магчымасці агурка, таму вы можаце пісаць свае тэсты API у простым фармаце 'Улічваючы, калі потым' і выкарыстоўваць усе ключавыя словы агурка, такія як 'Функцыя', 'Сцэнарый', 'Сцэнар', 'Прыклады', 'Тэгі'.

Я стварыў гэтую шпаргалку, каб дапамагчы ўсім, хто ўдзельнічае ў тэставанні 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 так:




karate-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 (атрымаць, апублікаваць, паставіць, выдаліць, выправіць)

@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 (атрымаць, апублікаваць, паставіць, заплаціць, выдаліць)

' дэф ’Выкарыстоўваецца для захоўвання значэння ў зменнай.


загаловак , 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 у іншы файл функцый, выкарыстоўваючы метад выкліку.


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

{
'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 у іншы файл функцый, выкарыстоўваючы метад выкліку, і адправіць зменную 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) |

У прыведзеным вышэй прыкладзе для стварэння тэстаў, заснаваных на дадзеных, выкарыстоўваюцца ключавыя словы 'Сцэнар сцэнарыя' і 'Прыклады'. Каб прачытаць кожны параметр, мы выкарыстоўваем вуглавыя дужкі

Выклік 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.