ランダム性は心の弱さ -- Rails においてテストデータをランダムに作ることについて
お気持ち
やめよう
何がおきたか
describe Foo do let(:left_foo) { Foo.new(value: 1000, bar: left_bar) } let(:left_bar) { BarMaster.all.sample } let(:right_foo) { Foo.new(value: 100, bar: right_bar) } let(:right_bar) { BarMaster.all.sample } it { expect(left_foo).to > right_foo } # left と right の bar が同じであるケースのとき落ちる end
あるいはこんなでもいい
describe Foo do let(:left_foo) { Foo.new(value: rand(100)) } let(:right_foo) { Foo.new(value: 0) } it { expect(left_foo).to > right_foo } # rand(100) の値域が 0..99 なので 0 を引くと落ちる end
なぜ避けるべきか
テストというのは書けばよいものではない。動作を担保し、オブジェクトに対する期待を明らかにするものである。
どのデータでも通ることを期待するならすべてのデータについてテストを回すべきだし、そうでないならそのテストで期待するものを満たす最小限のもので回すべきだ。
テストパターンにおけるランダム性の導入は、そうした最小の期待への考慮を放棄している、あるいは対象を正しく理解できていないように感じられる2。
なお QuickCheck のようなものを否定するわけではない。しかし QuickCheck のようなものは仕組みとして提供されるほうが望ましく、 Rails アプリケーションにおいてそのようなテストフレームワークを使っているのは稀だと思う。というか例があるなら聞きたい
実際には request spec がこのように書かれており、request spec で何を担保するのかというところが曖昧なようにも見えた。
お気持ち再掲
ランダムなデータにするのはやめて代表値を選んで使おう。
ほんとによくわかってないので質問しますが、テストにおいてマスタのデータがどれでもいいからって `foo_masters.sample` とかでランダム性をいれるのってメリットあります?
— はくどー (@HKDnet) 2018年1月26日
テストで何を担保するべきかが判断できないから「マスタからランダムに選んじゃおw」って気持ちになるんだと思っています
— はくどー (@HKDnet) 2018年2月19日