Help us understand the problem. What is going on with this article?

KarateによるAPIのシナリオテスト自動化 #01 Quick Start

More than 1 year has passed since last update.

はじめに

最近のシステム開発では、多様なデバイス/UIへの対応やマイクロサービスなどに対するニーズから、APIを中心とした「APIファースト(API-First)」な開発が増えてきています。
そのような中、当然ながらテストもAPIファーストに対応することになるのですが、API単体でテストするだけでなく、シナリオとしてテストしたいというケースが増えてきて、良いツールがないかと探していたところ、 @shimashima35 さんから、Karateを教えて頂きました。
プロジェクトで導入したところ、導入も比較的簡単で、使い勝手が良かったので、使い方をまとめたいと思います。

Karateとは?

Karateは、CucumberというBDD(ビヘイビア駆動開発)を行うためのフレームワークをJavaVM上に移植したもので、Gherkinの文法を自然言語に近い形で記述できるユニットテストツールです。

本家のサイトでは、以下のように紹介されています(日本語訳)。

Karateは、あらゆる種類のWebサービスへの一連の呼び出しをスクリプト化し、レスポンスが期待値どおりであるかを検証します。
複雑なリクエスト・ペイロードを作成し、レスポンス内のデータを走査し、レスポンスから次のリクエストにデータをチェーンすることも、簡単に行うことができます。 Karateのペイロード検証エンジンは、空白やデータ要素が実際に表示される順序の影響を受けずに、2つのJSONまたはXMLドキュメントの「スマートな比較」を行うことができます。また、選択したフィールドを無視することもできます。
Karateは、Cucumber-JVM上に構築されており、標準Javaプロジェクトのようにテストを実行してレポートを生成できます。 しかし、Javaの代わりに、HTTP、JSON、またはXMLを扱うように設計された言語でテストを記述します。これは、シンプルな方法です。

https://github.com/intuit/karate#web-services-testing-made-simple

自分としては、テスト記述がしやすい/内容が見やすいところが気に入っている点です。

KarateによるAPIテスト

利用準備

前提条件

  • Java SE 1.8.112 以上がインストールされていること
  • Maven 3.3 以上がインストールされていること

Mavenプロジェクトの作成

最初に、Karateのプロジェクトを作成します。
手動で必要なファイルを作成しても良いのですが、今回は、Karate Maven archetype を使って空のプロジェクトを作成します。

mvn archetype:generate \
-DarchetypeGroupId=com.intuit.karate \
-DarchetypeArtifactId=karate-archetype \
-DarchetypeVersion=0.7.0 \
-DgroupId=example -DartifactId=example-karate

出力されたファイルの構成は、以下のようになっています。

example-karate/
├── pom.xml
└── src
    ├── main
    │   └── java
    └── test
        └── java
            ├── examples
            │   ├── ExamplesTest.java
            │   └── users
            │       ├── UsersRunner.java
            │       └── users.feature
            ├── karate-config.js
            └── logback-test.xml
ファイル 説明
karate-config.js Karateの設定ファイルです。
logback-test.xml ログの設定ファイルです。無くても動作します。
ExamplesTest.java Karateのテスト実行クラスです。
UsersRunner.java シナリオごとのテスト実行クラスです。
users.feature サンプルのシナリオファイルです。

上記で注意する点として、karate-config.js.featureのファイルが、src/test/java配下に出力されています。
通常のMavenプロジェクトでは、テストに関するリソースファイルはsrc/test/resources配下に置くのが一般的ですが、Karateの場合、シナリオファイルとテストクラスを同じ場所に配置することが必要になります。

このため、pom.xmlには、以下の設定がされています。

  <build>
    <testResources>
      <testResource>
        <directory>src/test/java</directory>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </testResource>
    </testResources>
  </build>

テスト実施

テストの内容

上記で作成したプロジェクトの中では、既に「users.feature」というテストシナリオのファイルが用意されています。
中身を見ると、以下のような感じになっています(一部)。

Feature: sample karate test script    

Background:
* url 'https://jsonplaceholder.typicode.com'

Scenario: get all users and then get the first user by id

Given path 'users'
When method get
Then status 200

上記では、

  • Background:
  • Scenario:
    • "get all users and then get the first user by id" という内容のシナリオで、
  • Given-When-Then
    • 'users' というAPIに対して、
    • GET のメソッドで、
    • HTTPステータス 200 が返ってくることを期待する。

という内容をテストすることになります。
「Given」「When」「Then」 が基本の構成ですね。

変数を利用したり、レスポンスの内容を確認したりといったこともできますが、どのような記述をするのかは、以下を参照してください。

また、同じディレクトリに、 UsersRunner.java というテスト実行クラスがあります。
中身は空でも良いのですが、 @RunWith(Karate.class) のアノテーションが付与されている点に注意してください。

package examples.users;

import com.intuit.karate.junit4.Karate;
import org.junit.runner.RunWith;

@RunWith(Karate.class)
public class UsersRunner {

}

テストの実行

Mavenから、テストを実行します。

mvn clean test
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running examples.ExamplesTest
14:40:33.616 [main] INFO  com.intuit.karate - karate.env system property was: null
14:40:34.123 [main] DEBUG com.intuit.karate -
1 > GET https://jsonplaceholder.typicode.com/users
1 > Accept-Encoding: gzip,deflate
1 > Connection: Keep-Alive
1 > Host: jsonplaceholder.typicode.com
1 > User-Agent: Apache-HttpClient/4.5.4 (Java/1.8.0_172)

14:40:34.465 [main] DEBUG com.intuit.karate -
1 < 200
1 < Access-Control-Allow-Credentials: true
1 < CF-Cache-Status: HIT
1 < CF-RAY: 412731e2bad9a572-NRT
1 < Cache-Control: public, max-age=14400
1 < Connection: keep-alive
1 < Content-Type: application/json; charset=utf-8

・・・

2 Scenarios (2 passed)
17 Steps (17 passed)
0m1.677s
html report: (paste into browser to view)
-----------------------------------------
file:/MyWorkspace/example-karate/target/surefire-reports/TEST-examples.users.users.html

Tests run: 19, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.02 sec

  • 注意
    • Karate 0.7.0 以上では、Javaのバージョンは、1.8.112以上 である必要があります。1.9以上でもOKです。
    • マイナーバージョンにも注意。Javaのバージョンが不適切な場合は、以下のようなエラーが発生します。
java.lang.RuntimeException: evaluation of karate-config.js failed:
    at com.intuit.karate.ScriptContext.<init>(ScriptContext.java:150)
        ...
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: com.intuit.karate.exception.KarateException: javascript function call failed: 
ReferenceError: "karate" is not defined     

テスト結果の確認

Karateでは、以下のようなレポートが出力され、テストの実行内容が分かります。

karate-report.png

まとめ

まずは、Karateのチュートリアルを利用して、どのようにテストを実施できるのかを確認してみました。
比較的、直感的に理解できる内容になっているかと思います。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした