minitestによるベンチマークテストの記述
タグ: ruby / 初版公開: 2013-12-16

あるアルゴリズムのパフォーマンスが期待通りの計算量であるか、テストを記述したい事がある。Rubyのテスティングフレームワークであるminitestには、そのようなベンチマークテストを記述する機能が用意されている。

何か時間のかかる処理をするクラスを考える。 以下はひどい例だが 1000 x n回のループを回すクラスである。 このクラスのパフォーマンスが本当に線形かをテストしてみよう。

  • loop.rb
class Loop
	def do_loop(n)
		(1000 * n).times
	end
end

ベンチマークテストの記述にはminitest/benchmarkrequireしてやる必要がある。 ベンチマークテストはbenchをつけたメソッドに記述する。 assert_performance_linearは、パフォーマンスが線形かを確認するメソッドだ。 このメソッドはブロックに1, 10, 100, 1000, 10000の値を与えた時の、ブロックの実行速度を確認する。 ブロックを実行した結果、実行速度がy = a + bxの形で線形に推移すればテストが成功となる。

  • test_loop.rb
require 'minitest'
require 'minitest/autorun'
require 'minitest/benchmark'
require_relative 'loop.rb'

class Test < Minitest::Benchmark
	def setup
		@loop = Loop.new
	end 

	def bench_my_algorithm
		assert_performance_linear do |n| 
			@loop.do_loop(n)  
		end 
	end 
end

test_loop.rbの実行結果は以下のようになる。(注:マシンの性能により結果は異なるかも知れない) テストは成功しており、確かにloop.rbは線形のパフォーマンスを持っていることが確認できた。

$ ruby test_loop.rb 
Run options: --seed 29223

# Running:

bench_my_algorithm       0.000087        0.000724        0.007775        0.072802        0.734182
.

Finished in 0.826933s, 1.2093 runs/s, 1.2093 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

なおminitest/benchmarkにはassert_performance_linearの他にも様々なパターンの計算量をテストできるメソッドが用意されている。

メソッド 意味
assert_performance 実行時間を表示するのみ
assert_performance_constant 実行時間が常に一定かをテストする
assert_performance_exponential 実行時間がy = ae^(bx)の形で指数的に増加するかをテストする
assert_performance_logarithmic 実行時間がy = a + bln(x)*の形で対数的に増加するかをテストする
assert_performance_linear 実行時間がy = a + bxの形で線形に増加するかをテストする
assert_performance_power 実行時間がy = ax^bの形でべき乗で増加するかをテストする