RSpecで書く基底クラスのテスト実践例
これはなにか
RSpecを書くときに役立つ、実践例を書いた記事です。今回は
- 基底クラス
のテストを、改善前と改善後合わせて紹介します。他テスト(Minitestや他プログラミング言語)でも応用できる考え方なので、参考にしてみてください。
基底クラスをテストする
クラス例は以下の base.rb
になります。
それぞれのメソッドは
#greet
- 継承先で実装される想定
- ここでは
NotImplementedError
をraiseするだけ
#default_language
- 初期値は
:ja
- 継承先の必要に応じてオーバーライドされる
- 初期値は
といった単純なものになっています。
このクラスをどのようにテストするか考えていきます。
# base.rb class Base def initialize; end def greet raise NotImplementedError end def default_language :ja end end
改善前
普通に実装すると以下のようになると思います。
やっていることは Base
クラスをインスタンス化し、それぞれのメソッドをテストしているだけです。
# base_spec.rb require_relative '../base' require 'spec_helper' RSpec.describe Base do let(:baes) { described_class.new } describe '#greet' do it 'raises NotImplementedError' do expect { baes.greet }.to raise_error(NotImplementedError) end end describe '#default_language' do it 'returns :ja' do expect(baes.default_language).to eq :ja end end end
このテストの改善点
このテストには気になる点があります。それは
Baseクラスそのものをインスタンス化している
いう点です。
本来Baseクラスは、継承先で使われることを想定して作られているはずです。そのため、Baseクラスそのものをインスタンス化するといった使われ方は想定しておらず、実態とは異なる使い方でテストしていることになります。
基底クラスをテストするときは、安直にインスタンス化せず、継承させたあとにテストするべきです。
改善後
下が改善した基底クラスのテストになります。ポイントは
Class.#new
で派生クラスを作っている- 派生クラスをインスタンス化し、メソッドを呼んでいる
という点です。
派生クラスはClassを利用しています。これで簡単に、ガワになる継承先を作ることができました。
また、オーバーライド後の動作も確認できるように
when #default_language is overrided to :en
といったテストも作ることができました。より実践に沿った、テストケースになったと思います。
# base_spec.rb require_relative '../base' require 'spec_helper' RSpec.describe Base do let(:child_class) do Class.new(described_class) end let(:child_class_instance) { child_class.new } describe '#greet' do it 'raises NotImplementedError' do expect { child_class_instance.greet }.to raise_error(NotImplementedError) end end describe '#default_language' do it 'returns :ja' do expect(child_class_instance.default_language).to eq :ja end context 'when #default_language is overrided to :en' do let(:child_class) do Class.new(described_class) do def default_language :en end end end it 'returns :en' do expect(child_class_instance.default_language).to eq :en end end end end