相信做過接口測試的童鞋都習(xí)慣用Jmeter, Rest-Assured,Postman來編寫,可能對Karate還比較陌生。Karate DSL是一種新的API測試工具,它幫助以一種簡單的方式為基于API的BDD測試創(chuàng)建場景,而無需編寫步驟定義。之前項目用Karate做API測試,跟著開發(fā)寫了一段時間API測試代碼,我發(fā)現(xiàn)只需一點(diǎn)編程基礎(chǔ)就能輕松上手,現(xiàn)在Karate已經(jīng)成為Top10的API工具了,于是呼我決定普及一下,說一說Karate的框架搭建。
搭建Karate框架
1.創(chuàng)建一個gradle/maven工程,以下以gradle為例

image.png
2.然后在build.gradle文件里添加所需要得jar包
testCompile 'com.intuit.karate:karate-junit4:0.9.2'
testCompile 'com.intuit.karate:karate-apache:0.9.2'
3.再在build.gradle里添加以下配置(為什么要添加這個配置呢,因?yàn)镵arate測試有文件擴(kuò)展名.feature,一般gradle是將非java源文件存放在src/test/resources結(jié)構(gòu)中,配置這個得目的是將非java源文件與.java文件可以放在并排的位置,讓程序知道src/test/java下.java以外的文件都是資源文件)
sourceSets {
test {
resources {
srcDir file('src/test/java')
exclude '*/.java'
}
}

image.png
4.添加日志配置文件
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
target/karate.log
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

image.png
5.添加karate配置文件 karate-config.js
這里面的配置都是全局配置,在執(zhí)行每個Scenario前都會先獲取karate-config里的配置,當(dāng)然不存在這個文件也可以正常工作,具體根據(jù)你的工程來決定。karate.configure可以設(shè)置很多參數(shù)的值,具體可以參見git hub上Managing Headers, SSL, Timeouts and HTTP Proxy,這里有一個例子:

image.png
我們項目的配置:
function config() {
karate.configure('connectTimeout', 10000);//設(shè)置連接超時時間10s
karate.configure('readTimeout', 10000);//設(shè)置讀取超時時間10s
karate.configure('logPrettyRequest', true);//使用縮進(jìn)打印請求
karate.configure('logPrettyResponse', true);//使用縮進(jìn)打印響應(yīng)
karate.configure('retry', {count: 3, interval: 2000});//設(shè)置重試機(jī)制為3次,間隔時間為2s
var env = karate.env;//獲取java系統(tǒng)屬性“kara .env”,跑流水線時傳入env參數(shù)值,可以在不同的環(huán)境運(yùn)行api測試
if (!env) {
env = 'sit';
}
var config = read('classpath:karate-env.json')[env];
//這里是讀取env配置文件,相當(dāng)于我們是把上面例子的config文件寫在了一個karate-env.json文件中,由于我們有多個環(huán)境,每個環(huán)境以對象的形式存儲,當(dāng)想獲取某個環(huán)境的數(shù)據(jù)時,直接把對象名傳過去就能獲取到該環(huán)境的所有全局變量了
var customerInfo = karate.callSingle(
'classpath:apiTests/toC/common/customer/customer.feature', config);
//這里使用 karate.callSingle方法將配置傳入customer.feature文件下面,也可以使用call方法,callSingle與call方法的區(qū)別是執(zhí)行Scenario時call每執(zhí)行一次調(diào)一次,而callSingle只會在第一次執(zhí)行時調(diào)用,后面取之前執(zhí)行的緩存。customer.feature是用來獲取用戶token的
config.customerToken = customerInfo.customerToken;
config.customerId = customerInfo.customerId;
return config;
}

image.png
6.添加運(yùn)行案例的類
由于我們希望用例并行運(yùn)行,這里面我們使用Runner.parallel方法,可以參考官方文檔

image.png
下的DemoTestParallel類,如果是想串行運(yùn)行,直接用@RunWith(Karate.class)即可。
@Test
public void testParallel() {
Results results = Runner.parallel(getClass(), 5);//設(shè)置5個線程,并行運(yùn)行
generateReport(results.getReportDir());//輸出報告,在執(zhí)行每個特性之后,HTML報告將輸出到target/surefire-reports文件夾,你也可以自己定義報告輸出路徑
Assert.assertTrue(results.getErrorMessages(), results.getFailCount() == 0);
}
public static void generateReport(String karateOutputPath) {
Collection jsonFiles = FileUtils.listFiles(new File(karateOutputPath), new String[] {"json"}, true);
List jsonPaths = new ArrayList(jsonFiles.size());
jsonFiles.forEach(file -> jsonPaths.add(file.getAbsolutePath()));
Configuration config = new Configuration(new File("target"), "demo");//這里的target填寫報告文件根目錄,demo是填寫你的工程名稱
ReportBuilder reportBuilder = new ReportBuilder(jsonPaths, config);
reportBuilder.generateReports();
}
這里由于有些包沒有引入導(dǎo)致部分類找不到,需要在gradle下引入這些包:
testCompile 'commons-io:commons-io:2.5'
testCompile 'net.masterthought:cucumber-reporting:3.8.0'

image.png
在這里,如果我們不想要全部案例都運(yùn)行,我們可以使用@KarateOptions? 注解,
可以選擇想要運(yùn)行的案例,例子:
//運(yùn)行1個feature
@KarateOptions(features = "classpath:animals/cats/cats-post.feature")
//運(yùn)行多個feature
@KarateOptions(features = {
"classpath:animals/cats/cats-post.feature",
"classpath:animals/cats/cats-get.feature"})
//運(yùn)行features 在classpath:animals/cats路徑下的,且tag非@ignore的
@KarateOptions(features = "classpath:animals/cats", tags = "~@ignore")
//運(yùn)行tags為非@ignore,且含@customer、@bargain的
@KarateOptions(tags = {"~@ignore", "@customer", "@bargain"})
7、下面可以開始寫feature了,feature格式如下:
Feature \描述該特性的測試內(nèi)容
Background\這里是場景執(zhí)行的前置條件,一般在這里定義該特性的全局變量,在每個Scenario執(zhí)行前都會執(zhí)行
Scenario\這里是執(zhí)行步驟,如我要測試創(chuàng)建拼團(tuán)活動的api,對拼團(tuán)活動進(jìn)行創(chuàng)建,判斷是否創(chuàng)建成功
Feature: brief description of what is being tested
more lines of description if needed.
Background:
-this section is optional !
-steps here are executed before each Scenario in this file
-variables defined here will be 'global' to all scenarios
-and will be re-initialized before every scenario
Scenario: brief description of this scenario
-steps for this scenario
Scenario: a different scenario
-steps for this other scenario
如下,是一個創(chuàng)建商品的feature,在接口測試中,有幾個最重要的項:
1、url
2、header
3、請求參數(shù)
首先,我們要保證我們拿到的接口能正常調(diào)通,可以在postman試驗(yàn)

image.png
可以看到,我們在background里配了url及headers,background里的配置運(yùn)用于所有的scenario,然后定義參數(shù),這里我們使用read()方法讀取variables.json文件獲取入?yún)?,然后使用post方式發(fā)送請求,獲取response,比較response和期望的結(jié)果是否一致,如果一致就pass,不一致就拋出錯誤。

image.png
在運(yùn)行過程中,可能會拋出如下錯誤

image.png
那是因?yàn)槲覀儧]有添加log4j2的配置文件,只需添加log4j2.xml文件即可,或者把官方文檔karate.demo下的log4j2.properties的文件copy過來也行
如果我們想創(chuàng)建多個商品呢?我們可以寫一個方法執(zhí)行for循環(huán),調(diào)用feature多次,如下是用js寫的一個方法:
因?yàn)閯?chuàng)建多個商品時的code不一樣,所以需要傳入?yún)?shù)到createProduct.feature中,這里我們傳入了一個對象進(jìn)去

image.png
現(xiàn)在createProduct.feature也需要優(yōu)化一下了,把入?yún)鹘o對應(yīng)的值

image.png
然后,我們需要再寫一個feature,傳入開始和結(jié)束值,來調(diào)用該function,這樣就能創(chuàng)建多個商品了

image.png
當(dāng)然,Karate的功能遠(yuǎn)不止我說的這些,如果想要了解Karate更多用法的可以直接訪問它的官方文檔查看 ~https://github.com/intuit/karate