記事タイトルをみて「なんのこと?」と思った方もいるかもしれませんが、
RSpec や JUnit などに代表されるような example-based testing をせずに
property-based testing という方法でテストをする、というお話です。
property-based testing とは?
下記を参照ください
ランレングス圧縮(連長圧縮)をテスト
ランレングス圧縮を property-based testing でテストします。
テストは Ruby の property-based test 用のライブラリ rantly で行います。
ランレングス圧縮については下記を参照。
テストコード
require "rantly" require 'rantly/rspec_extensions' class RunLengthEncoding def self.encode(text) text.chars .chunk{ |c| c } .map{|e|e.last.size == 1 ? e.first : "#{e.first}#{e.last.size}" } .join end def self.decode(text) text.scan(/(.)(\d*)?/) .map{|e| e.last.empty? ? e : (e.first * e.last.to_i) }.join end end RSpec.describe 'example' do it do property_of { # 長さ50文字のランダムな英小文字文字列をテスト対象として生成する sized(50) {string(:lower)} # ランダムな値で5回テストを実行する }.check(5) { |i| encoded = RunLengthEncoding.encode(i) decoded = RunLengthEncoding.decode(encoded) print "encoded: #{encoded}", "\n" print "decoded: #{decoded}", "\n" # 入力した値とエンコードしたあとにデコードした値は同じになるはず expect(decoded).to eq(i) } end end
テスト実行
encoded: xjtrchxkqkoyfaelwsmcmjwvbhzlgyaiqaykcybdyeshj2icph decoded: xjtrchxkqkoyfaelwsmcmjwvbhzlgyaiqaykcybdyeshjjicph .encoded: mktch2qwdkhgacsfvdbtnmeluriebvtn2jp2hgpxplpoydakmf decoded: mktchhqwdkhgacsfvdbtnmeluriebvtnnjpphgpxplpoydakmf encoded: jnzorbkyptkogiovymryqvnucsodibgbjsmkpfvpw2m2pduvab decoded: jnzorbkyptkogiovymryqvnucsodibgbjsmkpfvpwwmmpduvab encoded: zydqdbsgqcpzuylksumxjtkoy2kuswxkewsgbgawvx2ckihcqu decoded: zydqdbsgqcpzuylksumxjtkoyykuswxkewsgbgawvxxckihcqu encoded: kor2dicitzaoayfjyiatjmspw3htymtzlvgbtkpqvsrdx2tpb decoded: korrdicitzaoayfjyiatjmspwwwhtymtzlvgbtkpqvsrdxxtpb success: 5 tests . Finished in 0.00205 seconds (files took 0.08749 seconds to load) 1 example, 0 failures
まとめ
example-based testing の場合は個別のテストケースをハードコートする必要がありましたが、
property-based testing では入力データのルールだけ決めておけばそれを元にランダムにデータを生成してくれることが確認できました。
サンプルなので5回だけ実行していますが、実際は様々なケースが実行されるようにもっと大きな回数を指定することになるでしょう。
最近 property-based testing を知って、現実問題どのくらいのケースで適用できるのか把握しきれていないこともあり、
他の方の情報を見てみたい思いがあります。
現状の私の理解としては
- property-based testing は example-based testing に比べて個別のケースをハードコートしないで良い分楽であり、ケース漏れしにくい
- property-based testing を適用する場合、処理を実行した結果が何らかの性質をもっていることを assert できる必要がある
このような性質があるため、基本的に property-based testing が使える場面では example-based testing のほうが好ましいが、
すべてのケースに適用できるわけではない。
というような理解をしているのですが、実際のところどうなのかよくわかっていません。
知りたいのは
- property-based testing にはどのようなメリットがあるのか?
- property-based testing を利用すべき対象の明確な基準は何か?
です。
より詳しい人の解説に期待です。
補足
Rantly の様々な機能については Qiita に多数の記事をまとめてあります。