APIテスト自動化ツールKarateをBDDツールとして使う

Karateとは

Karateは主にe2eテストを自動化するツール。cucumber的なfeatureファイルを書くとそれを実行できる。WebAPIのテストがその中心的ターゲット

github.com 

graalvmのjsライブラリで実現しているっぽいので、featureファイルからJavaも呼べる。

 

個人的にBDDというのが結構いいと思っていて、ビジネスルールの仕様なんかをビジネスサイドと意識合わせする場合に使えると思っている。アンクルボブはFitnesseというツールを作っている。

FrontPage

Fitnesseは名著『実践アジャイルテスト』でも紹介されていたもの

   

Fitnesseはアイデアはいいんだけど、wiki文書にテスト埋め込むとかまでしなくていいと思っていた。もっと簡便でメンテしやすい開発者フレンドリーなLiving Documentないかなあ、と。有名どころでは、Cucumberとかがあるんだけど、結局テストコードをドキュメントに合わせて2重に書くので、正直使いたくない。

Karateは簡潔なDSLAPI呼び出しの実行からアサーションまでをfeatureファイルに記述できる。かなり文書性が高く、テストコード特有の煩雑なノイズがない。普通に開発者が使うテストツールとしても使えると思う。

一つ思ったのが、ビジネスルール単体の仕様についてkarateで同様にかければユーザーとのコミュニケーションに便利なのではないか、と。 加えてSpring のBeanもテストしたいと思ってやってみた。

featureファイルはこんな感じ。

Feature: ビジネスロジックのテスト


  Background:
    * def CalcTestsRunner = Java.type('feature.calc.CalcFeatureTestsRunner')
    * table example
      | 入力値1 | 入力値2 | 期待結果 |
      | 10     | 20     | 30     |
      | 50     | 100    | 150    |
      | -10    | 10     | 0      |

  Scenario: シンプルなシナリオ
    * def x = 10
    * def result = CalcTestsRunner.testAdd(x,20)
    * assert result == 30

  Scenario Outline: データ駆動シナリオ データ例 <入力値1> + <入力値2> の結果は<期待結果>になる
    * def result = CalcTestsRunner.testAdd(<入力値1>,<入力値2>)
    * assert result == <期待結果>
    Examples:
      | example |
 

テストコードはこんな感じ

package feature.calc;

import com.example.demo.DemoApplication;
import com.example.demo.calc.CalcService;
import com.intuit.karate.junit5.Karate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(classes = DemoApplication.class)
public class CalcFeatureTestsRunner {

    static CalcService calcService;

    @Autowired
    public  void setCalcService(CalcService calcService) {
        CalcFeatureTestsRunner.calcService = calcService;
    }

    @Karate.Test
    Karate testCalc() {
        return Karate.run("calc").relativeTo(getClass());
    }

    public static int testAdd(int input1,int input2){
        //仕様を実現するコードを書いていく。流動的で良い
        return calcService.add(input1,input2);
    }

}

featureファイルにはプロダクションコードのクラスを直接書かない。リファクタリングするとき面倒になるから。 こんな感じで実行できる。

f:id:masatsugumatsus:20210319144510p:plain

レポートはこんな感じ

f:id:masatsugumatsus:20210319144755p:plain

githubにアップしました。

github.com