KarateでのAPIテストと同時にAssertJ-DBでデータの確認もやりたい

はじめに

Karateを使うとWeb APIのリクエスト&レスポンスのテストがとてもいい感じにできるが、そうすると今度は「POSTされたデータがちゃんとDBに入っているかどうか」とかも確認したくなってきてしまうもの。 そこでKarateでのテストシナリオ実行の際、AssertJ-DBでのデータのアサーションが行われるようにしてみる*1

環境

ポイント

Karateのfeatureファイルでは、Java.type('パッケージ+クラス名')Javaのクラスを参照できる。 これを利用し、あらかじめDBのテスト用メソッドをAssertJ-DBで書いておいて、それをfeatureファイルから呼び出すようにする。

参考: Calling Java | Karate

サンプルコード全体は下記のとおり。

github.com

やり方

JavaでDBのアサーションを行うメソッドを定義する

テストランナーのクラスにDBのアサーションを行うメソッドを定義しておく。下記サンプルの public static void assertTable(String expectedMessage) がそれ。

package demo;

// ...

@SpringBootTest(classes = DemoApplication.class)
public class DemoTestRunner {
    private static DataSource dataSource;

    @Autowired
    private void setDataSource(DataSource dataSource) {
        DemoTestRunner.dataSource = dataSource;
    }

    @Karate.Test
    Karate testAll() {
        return Karate.run().relativeTo(getClass());
    }

    public static void assertTable(String expectedMessage) {
        var table = new Table(dataSource, "messages");
        assertThat(table).hasNumberOfRows(1)
            .row(0)
            .column("message").value().isEqualTo(expectedMessage);
    }
}

Java.type() で使いたいのでメソッドは public static にする必要があり、それに合わせて DataSource をstaticフィールドにしている。 staticなDataSourceをインジェクションできるようにするため、 setDataSource() はだいぶ無理やり感がある…。

DBのアサーション自体は普通にAssertJ-DBで書けばよい。

featureファイルのシナリオでJavaのメソッドを呼び出す

こんな感じ。

Feature: Demo

  Background:
    * url baseUrl
    * def DemoTestRunner = Java.type('demo.DemoTestRunner')

  Scenario: Add a message
    Given path '/'
    And request { "message": "Hello" }
    When method post
    Then status 200
    And DemoTestRunner.assertTable('Hello')

  Scenario: Find messages
    # ...

Backgrounddef DemoTestRunner = Java.type('demo.DemoTestRunner') することで、引数で指定されたJavaのクラス(今回は DemoTestRunner)が使えるようにしておく。 シナリオでは DemoTestRunner.assertTable('Hello') のようにしてメソッドを呼び出す。

実行してみる

いつもどおりテストランナーのクラス(今回は DemoTestRunner)を実行すればよい。

IntelliJ IDEAだとテスト結果は普通にこんな感じで出てくる。

f:id:ser1zw:20210606182242p:plain

HTMLレポートも出てくる。

f:id:ser1zw:20210606182334p:plain

試しにこんな感じでテストをわざと失敗させてみると…

  Scenario: Add a message
    Given path '/'
    And request { "message": "INVALID" }
    When method post
    Then status 200
    And DemoTestRunner.assertTable('Hello')

失敗時の情報もちゃんと出てくる。よさそう。

f:id:ser1zw:20210606182713p:plain

f:id:ser1zw:20210606182812p:plain

*1:今回はAssertJ-DBを使っているが、別にAssertJ-DBである必要は無い。Javaのテスト用ライブラリなら同じように使えるはず。