2
0

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 3 years have passed since last update.

Rust でパラメタライズドテスト

Posted at

今回、Rustでテストコードを書いていて、パラメタライズドテストを省エネで書きたくなった。テストコードにしたって、何度も同じタイピングなんてしたくない。コピペなんて言語同断。

かなしいコード

例えば、こんなコード。

pub fn add(a:i32, b:i32) -> i32 {
    a + b
}

# [cfg(test)]
mod tests {
    #[test]
    fn test_add_1_1_returns_2() {
        assert_eq!(add(1, 1), 2);
    }
    #[test]
    fn test_add_0_100_returns_100() {
        assert_eq!(add(0, 100), 100);
    }
}

テストケースごとに似たような見た目のテストコードが増えていくことが目に見えている。

Go言語では、テストケースを構造体にまとめて、テストコードを見やすくすることを推奨している。
GitHub の Wiki にテーブル駆動テストという項目に掲載されている

また、Python の標準ライブラリの一つである unittest にも SubTest という似たような仕組みがある。

一方、Rustにはそのような仕組みがない。Rustは標準ライブラリが小さいことがよく知られているので仕方ない。だからといって、テストコードをコピペしてみっともない真似はしたくない。

Crates.io から探さずに自作する

プログラミング言語には、標準ライブラリ以外にサードパーティライブラリがあるため、さほど困らない。Rust には crates.io がある。JUnit にインスパイアされたという parameterized というライブラリを使うのが簡単そうだ。

Go や Python の例をみるとお分かりのとおり、シンプルな実装でできそうな気がしてくる。

Rust には強力な macro 機能がある。

マクロで作ってみた

# [cfg(test)]
mod tests {
   macro_rules! test_add {
        ($($name:ident: $value:expr, )*) => {
            $(
                #[test]
                fn $name() {
                    let (lhs, rhs, expected) = $value;
                    assert_eq!(crate::sample::add(lhs, rhs), expected);
                }
            )*
        };
    }

    test_add! {
        add1: (1, 1, 2),
        add2: (0, 100, 100),
    }
}

macro_rules を使って test_add マクロを生成する。今回は シンプルなコードなのでマクロを作る手間のほうが大きいが、このコードがサクッとかけるとライブラリに頼ることなくコードがかける。

関数単位のテストケースをマクロで生成しているので、テストが失敗してもほかのテストケースのテストは続行される。

なぜライブラリに頼らないか

ライブラリは便利だが、たくさんインストールすると依存性の解消や、脆弱性への対応などメンテナンスコストが高くなる。

ライブラリ選定に時間をかけるより、自分で書いたほうが早いということもある。盲目的に選択肢を絞るのではなく、いつでも多くの選択肢を見つけられるようにしておくとよい。

※とは言っても、マクロはデバッグが大変になるのであまりお勧めはしない。

実際にマクロを使ってコードを圧縮した事例

37行のコードが18行に圧縮された上、テストコードの意図が読み取りやすくなった。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?