9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KarateによるAPIのシナリオテスト自動化 #02 Reading By Example

Last updated at Posted at 2018-06-19

はじめに

前回は、Karate Maven archetype が出力する example を実行してみました。
今回は、そのファイルの内容を見ていき、Karateに対する理解を深めていきたいと思います。

KarateのExampleのファイル内容

Karate Maven archetype で出力される内容は、以下のような構成です。
以降で、ポイントとなるファイルの内容を確認していきます。

example-karate/
├── pom.xml
└── src
    ├── main
    │   └── java
    └── test
        └── java
            ├── examples
            │   ├── ExamplesTest.java
            │   └── users
            │       ├── UsersRunner.java
            │       └── users.feature
            ├── karate-config.js
            └── logback-test.xml

pom.xml

前提として、今回利用しているのは Karate 0.7.0 になります。

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.version>3.6.0</maven.compiler.version>
    <karate.version>0.7.0</karate.version>
  </properties>

dependencies では、以下の2つのライブラリが指定されています。

  • karate-apache
  • karate-junit4

2018/06/02現在、JUnit5には、まだ公式には対応されていないようです。

  <dependencies>
    <dependency>
      <groupId>com.intuit.karate</groupId>
      <artifactId>karate-apache</artifactId>
      <version>${karate.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.intuit.karate</groupId>
      <artifactId>karate-junit4</artifactId>
      <version>${karate.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

こちらは前回の注意点の再掲ですが、buildタグでは、以下のようにsrc/test/java をテストリソースに指定しておく必要があります(デフォルトは、scr/test/resources)。

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

karate-config.js

Karate の共通設定のファイルです。
デフォルトは、以下の内容。

function() {    
  var env = karate.env; // get system property 'karate.env'
  karate.log('karate.env system property was:', env);
  if (!env) {
    env = 'dev';
  }
  var config = {
    env: env,
	myVarName: 'someValue'
  }
  if (env == 'dev') {
    // customize
    // e.g. config.foo = 'bar';
  } else if (env == 'e2e') {
    // customize
  }
  return config;
}

基本的な設定内容は、以下を参照。

環境ごとに設定を切り替えたり、タイムアウト値などを設定できたりします。
httpsのREST-APIにアクセスすらう際にも、ここでSSLの設定をするらしい。

karate.configure('ssl', true);

examples/ExamplesTest.java

こちらは、テストケースを実行するためのクラス。
テストスイート(テストケースをグルーピングするもの)として振る舞います。
そのため、ディレクトリの構成は、後述する XxxRunner との関係性を意識する必要があります。

package examples;

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

@RunWith(Karate.class)
public class ExamplesTest {
    // this will run all *.feature files that exist in sub-directories
    // refer to https://github.com/intuit/karate#naming-conventions
    // for folder-structure recommendations and naming conventions
}

examples/users/UsersRunner.java, users.feature

こちらが、テストケースの本体の内容です。
Runnerのファイルと、featureのファイルがセットになりますが、1:1である必要はありません。
Runnerのテスト実行クラスがあるディレクトリのfeatureファイルが読み込まれ、テストシナリオとして実行されます。

UsersRunner.java
package examples.users;

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

@RunWith(Karate.class)
public class UsersRunner {
}
users.feature
Feature: sample karate test script    
    If you are using Eclipse, install the free Cucumber-Eclipse plugin from
    https://cucumber.io/cucumber-eclipse/
    Then you will see syntax-coloring for this file. But best of all,
    you will be able to right-click within this file and [Run As -> Cucumber Feature].
    If you see warnings like "does not have a matching glue code",
    go to the Eclipse preferences, find the 'Cucumber User Settings'
    and enter the following Root Package Name: com.intuit.karate    
    Refer to the Cucumber-Eclipse wiki for more: http://bit.ly/2mDaXeV

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

* def first = response[0]

Given path 'users', first.id
When method get
Then status 200

Scenario: create a user and then get it by id

* def user =
"""
{
  "name": "Test User",
  "username": "testuser",
  "email": "test@user.com",
  "address": {
    "street": "Has No Name",
    "suite": "Apt. 123",
    "city": "Electri",
    "zipcode": "54321-6789"
  }
}
"""

Given url 'https://jsonplaceholder.typicode.com/users'
And request user
When method post
Then status 201

* def id = response.id
* print 'created id is: ' + id

Given path id
# When method get
# Then status 200
# And match response contains user

テストスクリプト(featureファイル)の書き方

テストスクリプトの書き方については、主に以下の内容を参照してください。

基本構造

基本的な構造は、以下のようになります。

Feature: テストの概要
    テストの詳細内容の記述。
    複数行で記述可能。

Background:
# (optional)
# 全シナリオで共通的に利用するグローバル変数などを定義する。
# 各シナリオの前に実行される。

Scenario: シナリオの概要
# テストケースの記述
# 
# Given-When-Then-And -> テストの振る舞いの記述
# * def               -> 変数の定義
# * print             -> コンソールへの出力

Scenario: シナリオの概要
# テストケースの記述

テストシナリオ

Given-When-Then-And

テストシナリオの基本構文となるテストステップの記述です。
ひとつの Scenario: の中に、複数記述することができます。

  • Given
    • オブジェクトの作成や設定など、前提条件を記述する。
  • When
    • イベントやアクションを記述する。REST-APIの呼び出しなどを行う部分。
  • Then
    • 期待される結果を記述する。アサーションを使用し、実際の結果と記述した期待結果を比較する。
  • And
    • 直前のステップと同じ意味をもつ。複数の定義や条件を連続して記述する際に利用する。

以下のシナリオの内容を見てみます。
このシナリオでは、 JSONPlaceholder のAPIを利用しています。

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

Given path 'users'
When method get
Then status 200

* def first = response[0]

Given path 'users', first.id
When method get
Then status 200

Backgroundで、* url 'https://jsonplaceholder.typicode.com' と記述されているため、最初のテストステップでは、以下の内容を実行していることになります。

(1)Given path 'users'
(2)When method get
(3)Then status 200
  • (1) https://jsonplaceholder.typicode.com/users のAPI(userの一覧取得)をテストする。
  • (2)HTTP GET でアクセスする。
  • (3)HTTPステータス200 であることを確認する。

次のテストステップでは、前ステップのレスポンスを利用して、以下の内容を実行しています。

(1)* def first = response[0]

(2)Given path 'users', first.id
(3)When method get
(4)Then status 200
  • (1)一覧取得のレスポンスから、最初の1件を取得する。
  • (2)https://jsonplaceholder.typicode.com/users/{id} のAPIをテストする。
    • このとき、(1)で取得したデータの id をパラメータとして指定する。
  • (3)HTTP GET でアクセスする。
  • (4)HTTPステータス200 であることを確認する。

このようにして、テストシナリオを記述することができます。

また、以下のように、変数を指定してAPIの実行をすることも可能です。

* def user =
"""
{
  "name": "Test User",
  "username": "testuser",
  "email": "test@user.com",
  "address": {
    "street": "Has No Name",
    "suite": "Apt. 123",
    "city": "Electri",
    "zipcode": "54321-6789"
  }
}
"""

Given url 'https://jsonplaceholder.typicode.com/users'
And request user
When method post
Then status 201

拡張

example の内容にはありませんが、テストスクリプトのファイル内では、JavaScriptで関数を定義したり、さらにその中でJavaのクラスを呼び出したりすることができます。
これにより、多少複雑な処理が伴ったり、対象アプリの処理を実行したりする場合でも、テストシナリオを完結に記述することが可能になります。

例えば、現在日時を基準に、動的に日時を示す文字列を取得したい場合、以下のような記述で可能です。

* def getTime =
"""
function(min) {
  var dateFormatType = Java.type('java.text.SimpleDateFormat');
  var dateFormat = new dateFormatType("yyyy-MM-dd'T'HH:mm:ss.SSS+09:00");
  var date = new java.util.Date();
  date.setTime(date.getTime() + min*60*1000);
 
  return dateFormat.format(date);
}
"""

* def timestamp = {"timestamp": #(getTime(0))}
* print timestamp

これらの機能を使うことで、テストケースを効率よく作成していくことができそうですね!

詳細は、こちらを参照。

まとめ

example の内容を元に、Karateのテストの内容がどのような構成・記述になっているのかを確認しました。
テストシナリオの内容も、直感的に理解できる内容だと感じます。

Karateの機能は、ここに書いただけでなく、README の内容を見ると、他にもいろいろとあるようです。
その辺りは、別途、確認していきたいと思っています。

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?