KAKUTA TECH BLOG

Blog Article

Minitestでテストを自動化する

はじめに

プログラムを書いていると、「このメソッドは本当に期待した結果を返すのか」を確認する必要があります。毎回手動で確認するのは大変なので、Ruby では Minitest を使ってテストを自動化できます。今回は、基本的なテストの書き方と実行方法を紹介します。

参考リンク

Minitest とは?

Minitest は、Ruby で書いたプログラムが期待した通りに動作するかを確認するためのテストライブラリです。Ruby の公式ドキュメントでも、Minitest はテストスイートの作成や TDD、BDD などに利用できるライブラリとして扱われています。

そもそも「テスト」とは、プログラムに対して「この入力を与えたら、この結果になるはず」という期待を用意し、実際の結果と比較することです。例えば、2 つの数を足す add メソッドを作った場合、「add(2, 3) は 5 を返すはず」と考えられます。この期待通りの結果になるかをプログラムで確認するのがテストです。

テストを用意しておけば、プログラムを修正した後にも同じ確認を繰り返せます。手動で何度も実行して確認するのではなく、テストコードを実行するだけで結果を確認できるため、プログラムの変更によって以前動いていた処理が壊れていないかを確認しやすくなります。

Minitest の基本的なテストコード

まずは、Minitest を使った最も基本的なテストコードを見てみましょう。

require "minitest/autorun"

class SampleTest < Minitest::Test
  def test_sample
    assert_equal "RUBY", "ruby".upcase
  end
end

このコードでは、"ruby".upcase を実行した結果が "RUBY" になることを確認しています。

コードだけを見ると少し複雑に感じるかもしれませんが、実際に行っていることは、

  1. Minitest を読み込む
  2. テスト用のクラスを作る
  3. テストする処理を書く
  4. 期待する結果と実際の結果を比較する

という流れです。

Minitest を読み込む

最初の require は、Minitest をプログラムから利用できるようにするためのものです。

require "minitest/autorun"

require は、指定したライブラリやファイルを読み込むために使います。

ここで minitest/autorun を読み込むことで、Minitest のテストを実行するために必要な機能を利用でき、テストファイルを実行したときにテストが実行されます。

つまり、この 1 行は「これから Minitest を使ってテストします」という準備だと考えると分かりやすいです。

テスト用のクラスを作る

次に、テストをまとめるクラスを作ります。

class SampleTest < Minitest::Test

ここで使われている < は、Ruby でクラスを継承するときに使う記号です。

SampleTest が Minitest::Test を継承することで、Minitest が提供するテストの仕組みを利用できるようになります。

そのため、Minitest では基本的に、Minitest::Test を継承したクラスの中にテストメソッドを書いていきます。

クラス名の SampleTest は自由に名前を付けられますが、何のテストなのか分かる名前にすると管理しやすくなります。

テストメソッドを定義する

テストする処理は、test_ から始まるメソッドとして定義します。

def test_sample
  assert_equal "RUBY", "ruby".upcase
end

ここで重要なのが test_sample というメソッド名です。Minitest では、test_ で始まるメソッドがテストメソッドとして扱われます。

そのため、Minitest を実行すると test_sample がテストとして実行されます。

sample の部分は自由に名前を付けられるため、テストの内容が分かる名前を付けると読みやすくなります。

assert_equal で結果を確認する

assert_equal は、期待する値と実際の値が等しいかを確認するためのアサーションです。

アサーションとは、プログラムの結果が「こうなっているはず」という条件を確認する仕組みです。

assert_equal "RUBY", "ruby".upcase

このコードでは、2 つの値を比較しています。

期待する値        実際の値
"RUBY"      ←→   "ruby".upcase

"ruby".upcase を実行すると "RUBY" になるため、2 つの値は一致します。その結果、このテストは成功します。

このように、テストでは単にコードを実行するだけではなく、「実際の結果が期待した結果になっているか」まで確認することが重要です。

実際にメソッドをテストしてみる

ここからは、自分で作ったメソッドを Minitest でテストしてみます。

まず、2 つの数値を受け取って足し算する add メソッドを作ります。

def add(a, b)
  a + b
end

例えば、次のように実行すると 5 が返ります。

puts add(2, 3)
#=> 5

この add メソッドが正しく動作するかを Minitest で確認してみます。

テスト対象のコードを用意する

まず、add メソッドを calculator.rb というファイルに保存します。

def add(a, b)
  a + b
end

次に、テスト用の calculator_test.rb を作ります。

require "minitest/autorun"
require_relative "calculator"

class CalculatorTest < Minitest::Test
  def test_add
    assert_equal 4, add(2, 2)
  end
end

ここで require_relative "calculator" を使っているのがポイントです。

テストコードは calculator.rb とは別のファイルにあるため、そのままでは add メソッドを利用できません。そこで require_relative を使って、同じディレクトリにある calculator.rb を読み込みます。

これによって、テストコードから add メソッドを呼び出せるようになります。

add のテストを確認する

次の部分が実際のテストです。

assert_equal 4, add(2, 2)

これは、

期待する値 → 4
実際の値   → add(2, 2)

を比較しています。

add(2, 2) は 2 + 2 を計算するため、結果は 4 になります。

そのため、

assert_equal 4, 4

と同じ状態になり、テストは成功します。

もし add メソッドに間違いがあり、add(2, 2) の結果が 5 になっていた場合は、

assert_equal 4, 5

となるため、テストは失敗します。

このように、Minitest では「正しい結果を先に決めておき、実際の結果と比較する」ことで、プログラムが期待通りに動いているか確認します。

テストを実行する

テストファイルを作成したら、ターミナルから実行します。

calculator_test.rb があるディレクトリで、次のコマンドを実行します。

ruby calculator_test.rb

テストが成功すると、例えば次のような結果が表示されます。

Run options: --seed 57144

# Running:

.

Finished in 0.000290s, 3448.2773 runs/s, 3448.2773 assertions/s.

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

この結果には、テストがどのように実行されたのかが表示されています。

表示

意味

1 runs

テストメソッドが 1 件実行された

1 assertions

アサーションによる確認が 1 件実行された

0 failures

テストの期待値と実際の値が一致しなかったケースが 0 件

0 errors

テスト実行中に予期しないエラーが発生したケースが 0 件

0 skips

スキップされたテストが 0 件

特に、failures と errors は区別して覚えておくとよいでしょう。

failure は、テストとして実行できたものの、期待した結果と実際の結果が一致しなかった場合などに発生します。

一方、error は、テストを実行している途中で例外が発生するなど、テストそのものを正常に完了できなかった場合に発生します。

今回の結果では、

0 failures, 0 errors

となっているため、テストした処理は期待通りに動作し、テストの実行中にもエラーが発生しなかったことが分かります。

テストを自動化するメリット

Minitest の大きなメリットは、一度テストコードを作っておけば、同じ確認を何度も手動で行わなくてよいことです。

例えば、add メソッドを修正したとします。そのときに毎回、

puts add(2, 2)
puts add(10, 20)
puts add(100, 200)

のように自分で実行して結果を確認することもできます。

しかし、テストケースが増えてくると、すべてを手動で確認するのは大変です。

そこで、あらかじめテストコードを書いておけば、

ruby calculator_test.rb

を実行するだけで、複数の条件をまとめて確認できます。

さらに、後からプログラムを変更した場合でも、以前作ったテストをもう一度実行することで、変更によって以前の機能が壊れていないかを確認できます。

このように、Minitest は単に「バグを探すためのツール」というだけではなく、プログラムを変更しながら安全に開発していくためにも役立ちます。

まとめ

Minitest は、Ruby で書いたプログラムが期待した通りに動作するかを確認するためのテストライブラリです。テストコードを用意しておけば、同じ確認を何度も手動で行う必要がなくなり、プログラムを変更した後にも以前の動作が維持されているか確認しやすくなります。

今回の内容で特に重要なのは、「期待する結果」と「実際の結果」を比較するという考え方です。

  • require "minitest/autorun" で Minitest を読み込む
  • Minitest::Test を継承してテスト用のクラスを作る
  • test_ から始まるメソッドにテストを書く
  • assert_equal などのアサーションで結果を確認する
  • require_relative を使ってテスト対象のコードを読み込む
  • ruby ファイル名 でテストを実行する
  • failures と errors が 0 かどうかなどを確認してテスト結果を判断する

Minitest の基本的な仕組みを理解すると、手動で動作確認するだけではなく、「期待する動作をテストコードとして残しておく」という開発方法につなげられます。