mk2data で Markdown からテストデータ構築

mk2dataという小さなモジュールを作りました。マークダウンを使って、テストデータのセットアップや検証ができるようになるものです。

なんでこんなものを作ったのかと申しますと。

DB周りのテストを書く場合に、データのセットアップや検証のために、INSERTやSELECTを発行して確認するシーン、けっこうあると思います。でもこれ、面倒じゃないですか。プロダクションコードではバリバリORM使うのに、テストではあんまり使っていなかったり、標準APIを使って直接SQL発行してデータ作ってたり。そして煩雑になったSQL発行処理に、データのサマリや説明をつらつらとコメントしたりする。

かくいう わたしも、以下のようなことをしていたんですね。

dataSource.connection.use { conn ->
    conn.createStatement().use { stmt ->
        /*
        | id | name  | age | blood | birth_date |
        |----|-------|-----|-------|------------|
        | 10 | Alice | 20  | A     | 2000-03-05 |
        | 20 | Bob   | 18  |       | 2002-01-02 |
        */
        listOf("""
            INSERT INTO owners(
                id, name, age, blood, birth_date
            ) values (
                '10', 'Alice', 20, 'A', '2000-03-05'
            )
        """, """
            INSERT INTO owners(
                id, name, age, blood, birth_date
            ) values (
                '20', 'Bob', 18, null, '2002-01-02'
            )
        """).forEach(stmt::addBatch)
        stmt.executeBatch()
    }
}

実業務で使うテーブルなんかだと、更に種類が多かったりカラムの数も多かったりするので、例のようにテーブルのサマリを俯瞰できるようなコメントがついてると、レビューするにも、あとから自分が見返すにも、とても便利なんですが、一方で非常に面倒なんですよね。やっぱり。

メリットとしては以下のようなものがあります。

  • データを俯瞰しやすい
  • レビュアーに優しい
  • 未来の自分に優しい

一方で当然デメリットもあって。

  • 実際にコードで挿入されるデータと一致していない場合、大変な混乱をもたらす
  • テストデータを変更しようと思うとメンテが大変
  • 普通にめんどくさい

ただこれを2つ3つ書いたあたりで、あまりに面倒になってしまい、いやいや2020年の現代において、JavaにだってMarkdownパーサくらいあるだろ?と気がついてしまったんですね。そこで生まれたのがmk2dataなのです。

前置きが長くなりました。mk2dataは、このマークダウン形式のデータ表現と、実際のテストデータ挿入を統合、一致させるものです。使い方はいたってかんたんです。

要件

  • Java8

以下のように依存を追加してください。2020-03-08現在の最新バージョンは、1.1.0です。

<dependency>
    <groupId>com.yo1000</groupId>
    <artifactId>mk2data</artifactId>
    <version>1.1.0</version>
</dependency>

使い方

先程例に挙げたようなテストデータの場合、どのように使うのか確認してみます。

データのセットアップ

まずはデータのセットアップから。

dataSource.connection.use {
    MarkdownUtils.setup(it, """
        テーブル書式のマークダウン以外は何を書いても自由です
        テストデータの説明なんかも一緒に書いておくと良いでしょう

        | id | name  | age | blood | birth_date |
        |----|-------|-----|-------|------------|
        | 10 | Alice | 20  | A     | 2000-03-05 |
        | 20 | Bob   | 18  |       | 2002-01-02 |
        [ownews]

        テーブル名は ↑ の [owners] のようにキャプション書式で記述します

        | id   | name  | category | owners_id
        |------|-------|----------|-----------
        | 1000 | Max   | dogs     | 10
        | 1001 | Bella | dogs     | 10
        [pets]

        1つの文字列内に複数テーブルのテストデータを書くこともできます
        この場合、上から順にINSERTされていきます
        テーブル前後の | は省略可能です
    """)
}

これだけで先程のINSERTの例と同じように、テストデータのセットアップができます。べんりです。

データの検証

データのセットアップと同様に、プロダクションコードにより作成されたデータが、正しいものであるかどうかを確認するために、SELECTをつらつらと書いたりするシーンもあります。これもまたかなりの苦行です。mk2dataは、そんなシーンにも対応しています。

dataSource.connection.use {
    MarkdownUtils.expect(it, """
        データの検証も使い方はセットアップと同じです。
        違うのはメソッド名が expect になるという点のみです。

        | id | name  | age | blood | birth_date |
        |----|-------|-----|-------|------------|
        | 10 | Alice | 20  | A     | 2000-03-05 |
        | 20 | Bob   | 18  |       | 2002-01-02 |
        [ownews]

        | id   | name  | category | owners_id
        |------|-------|----------|-----------
        | 1000 | Max   | dogs     | 10
        | 1001 | Bella | dogs     | 10
        [pets]
    """)
}

また、AssertJのようなフレームワークでアサーションしたい場合には、メソッドの後ろに以下のようなコードを付け足すことができます。

dataSource.connection.use {
    MarkdownUtils.expect(it, """
        ..
    """) { fetchedCount, row ->
        println(row) // アサーション対象になっている行データにもアクセス可能
        assertThat(fetchedCount).isEqualTo(1)
    }
}

実装では、マークダウンから与えられたすべてのカラムをWHEREに設定したSELECTを投げて、これが何件フェッチできたかによってデータ検証をしています。

かんたんな紹介でしたが、以上がmk2dataの主な機能です。とても便利なのでぜひ使ってみてください。

参考

avatar

Written by yo1000 | YO!CHI KIKUCHI
Loves 🌱 Spring, 🦢 Pelikan fountain pen and 🦁 FINAL FANTASY VIII