Rustでテストデータを用意するためのtestfixturesライブラリを作った

Rustでテストデータを用意するためのtestfixturesライブラリを作った
TaKO8Ki
July 24, 2020

こんにちは、 TaKO8Ki です。

RustでDB操作を伴う関数をテストしたいなーと考えていた時にいい感じのライブラリが見当たらなかったので作ってみました。

DB操作を伴う関数をテストする時は大きく分けて以下の2パターンあると思うのですが、今回作ったのは前者の方に焦点を当てたライブラリです。

  • テスト用のDBを用意して、そこに実際にテストデータを用意してテストを行う。
  • database poolなどモックできるような実装にすることで、実際にはsqlの実行を行わずにテストを行う。

使い方

このライブラリは sqlx をベースにしており、async runtimeは tokioasync-std に対応しています。

インストールする際は下記のようにします。

async-std

# Cargo.toml
[dependencies]
testfixtures = "0.1"
sqlx = "0.3"
chrono = "0.4.11"

tokio

[dependencies]
testfixtures = { version = "0.1", default-features = false, features = [ "runtime-tokio" ] }
sqlx = { version = "0.3", default-features = false, features = [ "runtime-tokio", "macros" ] }
chrono = "0.4.11"

実際に使う時にはまず、下記のようなfixturesファイルを作ります。この際、YAMLファイルの名前をテーブル名と対応させます。

# fixtures/todos.yml
- id: 1
  description: buy a new camera
  done: true
  progress: 10.5
  created_at: 2020/01/01 01:01:01
- id: 2
  description: meeting
  done: false
  progress: 30.0
  created_at: 2020/01/01 02:02:02

その後、それぞれのテストの中でfixtureをロードします。

#[cfg(test)]
mod tests {
    use chrono::Utc;
    use sqlx::MySqlPool;
    use std::env;
    use testfixtures::MySqlLoader;

    #[async_std::test]
    async fn test_something() -> anyhow::Result<()> {
        let pool = MySqlPool::new(&env::var("DATABASE_URL")?).await?;
        let loader = MySqlLoader::new(|cfg| {
            cfg.location(Utc);
            cfg.database(pool);
            cfg.skip_test_database_check();
            cfg.paths(vec!["fixtures/todos.yml"]);
        })
        .await?;

        // fixturesをロードする
        loader.load().await.unwrap();

        // テスト実行

        Ok(())
    }
}

さらに詳しくは README を見てください!

現状できること

このライブラリは go-testfixtures/testfixtures を参考に作ったものなのですが、それと比較すると、まずDBに関しては、現状はMySQLのみに対応しており、現在、PostgreSQLに対応させようとしているところです。さっと実装できそうであればSQLiteにも対応させたいと思います。

また、オプションに関しては、下記のような実装ステータスです。

オプション実装済みかどうか?
fixtureファイルをfile pathを指定して読み込むtrue
fixtureファイルをディレクトリ単位で読み込むtrue
上記両方を混在させてロードするtrue
database名がテスト用か確認するtrue
locationを指定する(現状意味ないけど)true
fixtureファイル内でtemplateを使えるようにする( 参考 )false

割といい感じに出来上がった気がするので、もしよかったら使ってみてください!
PR、starも待ってます!