Magnolia Tech

いつもコードのことばかり考えている人のために。

『実践プロパティベーステスト ― PropErとErlang/Elixirではじめよう』は、言語に関係なくプロパティベーステストを学びたい人はすぐ買うべき

Erlang/ElixirのPropErというライブラリをベースに、プロパティベーステストの考え方、テストの実践的な書き方を学ぶための本です。

『実践プロパティベーステスト ― PropErとErlang/Elixirではじめよう』www.lambdanote.com

書名だけ見ると「Erlang/Elixirは使ってないからなー」と避けてしまうかもしれませんが、それはもったいなく、言語に関係なく、”プロパティベーステスティング”という手法の本質的な活用の仕方が学べるようになっています。


ここしばらくScalaScalaCheckというプロパティベーステストライブラリを使ってテストを書くことに挑戦していたのですが、今一つより良い書き方が分からず、何か参考になる情報が無いかと探しているタイミングでこの本が出版されたので、早速買って読んでみました。

プロパティベーステストは、テストコードを「テスト対象のコードが満たすべき特質(プロパティ)」と、「テストデータの生成」を分離し、予め用意された「ジェネレータ」が大量のテストデータを自動かつ、ランダムに生成することで、手動で作ったテストデータだけでは考慮できていなかったルートのバグを炙り出す手法です。

例えば、「二つのリストの長さをそれぞれ計算してから足した結果と、リストを連結した後に計算した長さは一致する」という特質(プロパティ)をScalaCheckで書くと以下のようになります。

scala> val propConcatLists = forAll { (l1: List[Int], l2: List[Int]) =>
  l1.size + l2.size == (l1 ::: l2).size }
Check the property!

scala> propConcatLists.check
+ OK, passed 100 tests.

これだけで100個のパターンが自動で生成されてテストされます。

当然、特質を満たさないパターンがあればエラーになります。

scala> val propSqrt = forAll { (n: Int) => scala.math.sqrt(n*n) == n }

scala> propSqrt.check
! Falsified after 2 passed tests.
> ARG_0: -1
> ARG_0_ORIGINAL: -488187735

負の数を二乗して、平方根(sqrt)を元の数とは一致しないので、エラーになりました。ARG_0や、ARG_0_ORIGINALという二つのパターンが並んでいますが、これは一度発見したエラーパターン(-488187735)を元に、よりシンプルなパターン(-1)を自動的に探してくれるShrinkingという概念によるもので、プロパティベーステストのライブラリでは必ず用意されている機能の一つです。賢いですね(そんなに上手くいかないことも多いですが)。


このように、話を聞くと「これは凄い!」と思って早速書き始めたくなるプロパティベーステストですが、実際に描き始めるとサンプルコードに出てくるようなシンプルは事例はよくても、実際のコードに対する適切なデータの生成を考えていくと、とても苦労して、いくつもの壁にぶつかります。

本書は、このような「プロパティベーステストを書こうとするとぶつかる疑問点」を上手く解消するように、Erlang/ElixirのPropErというライブラリをベースに、プロパティベーステストの考え方、テストの実践的な書き方が学べるように構成されています。

「どうやってテストしたい内容を汎化するか」「どうやって不変条件を積み重ねて、コードの特質の確らしさを積み重ねていくか」「用意されたジェネレータを元に、自分が欲しいデータを組み立てていくか」「そもそもテストってどうやって組み立てていくのか」「実際のビジネスロジックに応じたテストはどうやって書くのか」

プロパティベーステストを書き始めてぶつかり疑問に対する答えがみんな書いてあります。凄い!


プロパティベーステストでは、具体的なパターンを一度「汎化させる」という抽象化のステップが間に入るので、これまでの「自分で思いついたテストパターンを挙げていく」だけでおわらず、「そもそもこのテストパターンを汎化させると、どんな構造になるのか?」を考える必要が出てきて、改めてテストしようとするコードについて考えることとなり、コードに対するより深い理解が得られることになります。

そのための時間(テストを考える時間だけでなく、大量に生成されたテストを都度実行する時間も必要です)と、膨大なテストの自動生成による品質確保(品質の安定化ともいえます)というトレードオフをどのように判断するかによってプロパティベーステストを導入する否かが決まってきますが、まずは一度じっくりその考え方を学んでみないと、そのトレードオフも判断できないので、ぜひ本書で学んでみることをお勧めします。

なにより、この時代に「Erlang/Elixirのプロパティベーステストの本を和訳して商業出版しよう!」という心意気がいいですよね、こんな本は買っていかないといけないのです!