itで期待する振る舞いを定義しよう

学習の目標

本章では、以下の内容を学習します。

  • RSpecのitブロックの基本概念と役割を理解する
  • テストケースを明確に記述するための効果的な方法を習得する
  • describeとcontextの中でのitブロックの適切な配置を学ぶ
  • 複数のテストケースを効率的に整理する方法を習得する
  • テストコードの可読性を高める実践的なテクニックを身につける

はじめに

テストケースを構造的に整理するため、前回まではdescribecontextの使い方を学んできました。これらを使って作った枠組みの中で、今回は実際にテストを記述する方法を説明します。

RSpecでは、個々のテストケースを記述するためにitというブロックを使用します。このitブロックは、テストコードの中で最も基本的かつ重要な要素の一つです。なぜなら、実際の検証が行われるのはこのitブロックの中だからです。

itブロックの特徴的な点は、「期待する動作」を検証する仕組みだという点です。つまり、「このプログラムがこのように動くはずだ」という期待を、テストとして表現することができるのです。そして、その期待通りに動くかどうかを自動的に確認できるようになります。

itブロックの役割と意味

itブロックでは、テストの目的を文章のように説明します。例えば「2足す2は4になる」というように、テストで確認したい内容を日本語で明確に記述することができます。

この方法には大きなメリットがあります。プログラミングに慣れていない方でも、テストの内容を理解しやすくなるのです。また、後からコードを読み返す時にも、何をテストしているのかがすぐにわかります。

そして、itブロックの中に実際の検証処理を記述します。多くの場合、expectを使って期待する結果を確認する処理を書きます。このexpectの詳細については次回説明しますが、今回はitブロックの中でどのように使われるかを見ていきましょう。

itの基本的な使い方

それでは、具体的なコードを通してitの使い方を見ていきましょう。新しくファイルを作成して実行してみます。

spec/calculator_spec.rbというファイルを作成し、以下のコードを記述してください。

RSpec.describe '計算機' do
it '2足す2は4になる' do
expect(2 + 2).to eq(4)
end
end

このコードについて簡単に説明しましょう。まず、itの後に続く文字列は、テストの目的を説明する文章です。ここには「どのような動作を期待しているか」を明確に記述します。この例では「2足す2は4になる」という期待を表現しています。

また、ブロックの中には、実際の検証処理を記述します。この例ではexpect(2 + 2).to eq(4)という記述で、「2+2の結果が4と等しいことを期待する」という検証をしています。

ファイルを保存したら、ターミナルで以下のコマンドを実行してテストを走らせてみましょう。

bundle exec rspec spec/calculator_spec.rb

テストが成功すると、次のような出力が表示されるはずです。

計算機
2足す2は4になる
Finished in 0.00379 seconds (files took 0.08893 seconds to load)
1 example, 0 failures

この結果から、私たちの期待通り「2+2=4」となり、テストが成功したことがわかります。もし計算結果が異なる場合(例えばexpect(2 + 2).to eq(5)としていた場合)、テストは失敗し、エラーメッセージが表示されます。

テストケースを追加する

実際のアプリケーションでは、一つの機能に対して複数のテストケースを記述することが一般的です。それぞれのケースを別々のitブロックで表現することで、テストの意図がより明確になります。

spec/calculator_spec.rbを以下のように修正して、複数のテストケースを追加してみましょう。

RSpec.describe '計算機' do
describe '足し算' do
it '2足す2は4になる' do
expect(2 + 2).to eq(4)
end
it '1足す4は5になる' do
expect(1 + 4).to eq(5)
end
end
describe '引き算' do
it '5引く3は2になる' do
expect(5 - 3).to eq(2)
end
end
end

ファイルを保存したら、再度テストを実行してみましょう。

bundle exec rspec spec/calculator_spec.rb

すると、以下のような結果が表示されるはずです。

計算機
足し算
2足す2は4になる
1足す4は5になる
引き算
5引く3は2になる
Finished in 0.00423 seconds (files took 0.08776 seconds to load)
3 examples, 0 failures

このコードでは、計算機の「足し算」と「引き算」の機能をテストしています。さらに、足し算の中でも計算する数字が異なるパターンはそれぞれ別々のitブロックで検証しています。

このようにテストケースを分けることで、どのケースが成功し、どのケースが失敗したのかを明確に把握できるようになります。また、後から新しいテストケースを追加するのも容易になります。

意図的にテストを失敗させる

テストの挙動をより深く理解するために、意図的にテストを失敗させてみましょう。spec/calculator_spec.rbを以下のように修正します。

RSpec.describe '計算機' do
describe '足し算' do
it '2足す2は4になる' do
expect(2 + 2).to eq(5) # わざと間違えています
end
it '1足す4は5になる' do
expect(1 + 4).to eq(5)
end
end
describe '引き算' do
it '5引く3は2になる' do
expect(5 - 3).to eq(2)
end
end
end

このコードでは、最初のテストケースで「2+2=5」という明らかに間違った期待をしています。このテストを実行すると、以下のようなエラーメッセージが表示されるはずです。

計算機
足し算
2足す2は4になる (FAILED - 1)
1足す4は5になる
引き算
5引く3は2になる
Failures:
1) 計算機 足し算 2足す2は4になる
Failure/Error: expect(2 + 2).to eq(5)
expected: 5
got: 4
(compared using ==)
# ./spec/calculator_spec.rb:4:in `block (3 levels) in <top (required)>'
Finished in 0.03642 seconds (files took 0.08825 seconds to load)
3 examples, 1 failure

このエラーメッセージからは、「期待していた値は5だが、実際に得られた値は4だった」ことがわかります。また、どのテストケースが失敗したのかも明確に示されています。

このように、itブロックを使って個々のテストケースを分けておくことで、エラーが発生した場合にも問題を特定しやすくなります。また、複数のテストケースがある場合でも、エラーが発生したケースだけ修正すればよいので、効率的にテストを修正できます。

itブロック内の構造

itブロックの中には、実は複数のexpect条件を記述することもできます。例えば以下のようなコードを追加してみましょう。

RSpec.describe '計算機' do
# 既存のテストケースはそのままで...
it '四則演算の結果が正しい' do
expect(2 + 2).to eq(4)
expect(5 - 3).to eq(2)
expect(2 * 3).to eq(6)
expect(6 / 2).to eq(3)
end
end

このテストを実行すると、全てのexpectが正しいため、テストは成功します。しかし、1つのitブロックに複数の検証を記述すると、テストが失敗した時に問題の箇所を特定するのが難しくなるというデメリットがあります。

例えば、上記のコードを以下のように修正して、わざとエラーを入れてみましょう。

RSpec.describe '計算機' do
# 既存のテストケースはそのままで...
it '四則演算の結果が正しい' do
expect(2 + 2).to eq(4)
expect(5 - 3).to eq(2)
expect(2 * 3).to eq(7) # わざと間違えています
expect(6 / 2).to eq(3)
end
end

このテストを実行すると、エラーメッセージは以下のようになります。

Failures:
1) 計算機 四則演算の結果が正しい
Failure/Error: expect(2 * 3).to eq(7)
expected: 7
got: 6
(compared using ==)

エラーメッセージから、掛け算の部分(2 * 3)が間違っていることはわかりますが、「四則演算の結果が正しい」というテスト全体が失敗したと表示されます。これだと、大きなテストケースの中の一部がエラーの場合、どこが問題なのかを特定するのが難しくなります。

そのため、一般的には「1つのitブロックには1つの検証(または密接に関連した少数の検証)」というルールに従うことが推奨されています。つまり、上記の四則演算のテストなら、以下のように分けた方が良いでしょう。

RSpec.describe '計算機' do
# 既存のテストケースはそのままで...
describe '四則演算' do
it '足し算の結果が正しい' do
expect(2 + 2).to eq(4)
end
it '引き算の結果が正しい' do
expect(5 - 3).to eq(2)
end
it '掛け算の結果が正しい' do
expect(2 * 3).to eq(6)
end
it '割り算の結果が正しい' do
expect(6 / 2).to eq(3)
end
end
end

このように分けることで、どの計算がエラーになっているのかを明確に特定できるようになります。

テストの意図を明確にする

itブロックの文字列部分は、テストの意図を表現する重要な場所です。この部分をどのように記述するかによって、テストコードの読みやすさが大きく変わります。

良い例:

  • it '2足す2は4になる'
  • it '無効な入力の場合はエラーを返す'
  • it 'ユーザー名が空欄の場合は無効になる'

これらは、テストの意図が明確に伝わる文章になっています。

あまり良くない例:

  • it 'テスト1'
  • it '正常系'
  • it 'バリデーション'

これらは、何をテストしているのかが具体的に伝わらない曖昧な表現です。

テストの意図を明確に表現することで、テストコードそのものがドキュメントとしての役割も果たすようになります。そのため、itブロックの文字列部分は丁寧に記述することをおすすめします。

まとめ

本章では、RSpecにおけるitブロックについて学習しました。以下の内容をマスターできたことと思います。

  • itブロックは、プログラムの振る舞いを1つ1つ検証するための基本的な構造である
  • itブロックは「期待する動作」を検証する仕組みとして機能する
  • テストの目的を日本語で明確に記述することで、テストの意図が伝わりやすくなる
  • 1つのitブロックには基本的に1つの検証を記述することが推奨される
  • describecontextと組み合わせることで、テストコードを効率的に整理できる

次回は、テストの条件を具体的に記述するためのexpectと、様々なマッチャーについて学習します。この組み合わせによって、より詳細かつ正確なテストを記述できるようになります。

このセクションは有料サブスクリプションへの登録、またはログインが必要です。完全なコンテンツにアクセスするには、料金ページ(/pricing)をご覧ください。購入済みの場合は、ログインしてください。

Basicプランでより詳しく学習

この先のコンテンツを読むにはBasicプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。

作成者:とまだ
Previous
contextでテスト条件を整理しよう