Karate е инструмент за тестване на API на OpenSource, разработен от Питър Томас от Intuit. Карате е изградено върху HttpClient и Cucumber и има собствен DSL, за да направи API тестването много лесно. Въпреки че съществува от почти година, той е узрял много бързо и разполага с всички възможности, очаквани от инструмента за тестване на API.
Тъй като карате е разположен върху краставицата, той наследява всички функционалности на краставицата, така че можете да напишете своите API тестове в прост формат „Дайте кога след това“ и да използвате всички ключови думи за краставицата, като Feature, Сценарий, Сценарий, Примери, Маркиране на Feature.
Създадох този измамен лист, за да помогна на всеки, който участва в тестването на API, давайки примери за това как да използвате инструмента за карате.
Моля обърнете внимание , този мамят е само върхът на айсберга. Карате има много други функции, които не са споменати тук. Този списък е само най-често срещаните операции, които обикновено се използват при тестване на API.
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 по следния начин:
Тук можете да създавате променливи, които имат глобален обхват. Карате чете този файл, преди да изпълни какъвто и да е сценарий. Това е много полезно при превключване на среди, които специфични променливи се използват за различни среди
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; }
@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)
' деф ’Се използва за съхраняване на стойност в променлива.
заглавна част , URL адрес , заявка , метод , статус , отговор са всички ключови думи на карате, формиращи DSL. За пълния списък с ключови думи посетете Intuit.
В горния пример отговорът е във формат JSON, така че можем да използваме вградената в карате нотация JsonPath, за да анализираме отговора.
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', }
Можем да прочетем конкретна променлива в извикания файл на характеристиките, която се предава от извикващ файл на характеристиките
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
Можем да изпълним сценариите във файла на характеристиките, като използваме 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“.
Той също така създава доклад за краставици за визуализиране на резултатите от тестовите писти.
mvn clean test -DargLine='-Dkarate.env=staging' -Dtest=TestRunner_FR
Тук изпълняваме класа TestRunner_FR и настройваме средата като етап.
Във файл с функции имаме възможност да изпълним и 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) |
Примерът по-горе използва ключови думи за Сценарий на краставицата и Примери за създаване на тестове, управлявани от данни. За да прочетем всеки параметър, използваме ъгловите скоби
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.