ケース1
悪い書き方: it
に文脈を書いてしまっている。
describe '#hoge' do
it '引数がfooの場合barを返す' do
expect(hoge('foo')).to eq 'bar'
end
end
良い書き方: context
を使いましょう。it
には期待値だけを書きましょう。
describe '#hoge' do
context '引数がfooの場合' do
let(:args) { 'foo' }
it 'barを返す' do
expect(hoge(args)).to eq 'bar'
end
end
end
ケース2
あまり良くない書き方: its
を使っていない
describe '#hoge' do
it { expecte(hoge).to eq 'bar' }
end
良い書き方: its
を使いましょう。
its(:hoge) { is_expected.to eq 'bar' }
(its
を使うためにはrspec-its
gemが必要です。)
ケース3
悪い書き方: context
の内容が直下のbefore
の内容と違う。
context 'ログインしている場合' do
it '名前が表示される' do
login(user)
is_expected.to have_content 'Alice'
end
end
良い書き方: before
を使ってcontext
の内容とbefore
の内容が同じになるようにしましょう。
context 'ログインしている場合' do
before { login(user) }
it '名前が表示される' do
is_expected.to have_content 'Alice'
end
end
ケース4
悪い書き方: let
を使っていない。
describe User do
before { @user = create(:user, name: 'Alice') }
it '#name' do
expect(@user.name).to eq 'Alice'
end
end
良い書き方: let
を使いましょう。
describe User do
let(:user) { create(:user, name: 'Alice') }
it '#name' do
expect(user.name).to eq 'Alice'
end
end
ケース5
悪い書き方: describe
とsubject
が一致しない(subject
を使っていない)。
describe User do
let(:user) { create(:user, name: 'Alice') }
it '#name' do
expect(user.name).to eq 'Alice'
end
end
良い書き方: describe
の内容とsubject
は一致させましょう。
describe User do
let(:user) { create(:user, name: 'Alice') }
subject { user }
its(:name) { is_expected.to eq 'Alice' }
end
これでits
も使えるようになります。
ケース6
悪い書き方: factory_girlのリレーションを使っていない。
user_factory.rb
FactoryGirl.define do
factory :user do
company_id { rand(1..100) }
name { Faker::Name.name }
end
end
let(:company) { create(:company) }
let(:user) { create(:user, company_id: company.id) }
良い書き方: リレーションを使いましょう。
user_factory.rb
FactoryGirl.define do
factory :user do
company
name { Faker::Name.name }
end
end
let(:company) { create(:company) }
let(:user) { create(:user, company: company) }
ケース7
あまり良くない書き方: shoulda
を使っていない。
context 'keyが空の場合' do
before { user.key = '' }
it { is_expected.to be_invalid }
end
良い書き方: shoulda
を使いましょう。
it { is_expected.to validate_presence_of(:key) }
他に何ができるかは https://github.com/thoughtbot/shoulda-matchers を見てください。
かなり色々できます。
ケース8
悪い書き方: should
を使っている。
it { foo.should eq 'bar' }
良い書き方: expect
を使いましょう。
it { expect(foo).to eq 'bar' }
ケース9
あまり良くない書き方: 重いテストをまとめていない。
RSpec.feature 'Project List Page', js: true do
before { visit project_list_path }
subject { page }
it { is_expected.to have_content 'ID' }
it { is_expected.to have_content '名前' }
it { is_expected.to have_content '受注先会社名' }
it { is_expected.to have_content '開始日' }
it { is_expected.to have_content '終了日' }
it { is_expected.to have_content '契約日' }
end
良い書き方: 重いテストは1つにまとめましょう
「1つのテストで確認することは1つだけ」は正しいことですが、テストの実行にかかる時間とトレードオフです。
仮想ブラウザを使ったテストなどの重いテストはまとめましょう。
RSpec.feature 'Project List Page', js: true do
before { visit project_list_path }
subject { page }
it '各項目が存在すること' do
is_expected.to have_content 'ID'
is_expected.to have_content '名前'
is_expected.to have_content '受注先会社名'
is_expected.to have_content '開始日'
is_expected.to have_content '終了日'
is_expected.to have_content '契約日'
end
end
aggregate_failuresの使用
上記の例について、aggregate_failuresで各expectを囲ってやることでテストがfailした時にどの項目で落ちたのかがわかるようになります。
RSpec.feature 'Project List Page', js: true do
before { visit project_list_path }
subject { page }
it '各項目が存在すること' do
aggregate_failures 'testing items' do
is_expected.to have_content 'ID'
is_expected.to have_content '名前'
is_expected.to have_content '受注先会社名'
is_expected.to have_content '開始日'
is_expected.to have_content '終了日'
is_expected.to have_content '契約日'
end
end
end
spec_helperに以下の記述を追加することでも同じことが可能です。
config.define_derived_metadata do |meta|
meta[:aggregate_failures] = true unless meta.key?(:aggregate_failures)
end
まとめ的な
specとは仕様という意味です。つまり、rspecは仕様書です。
その点をふまえて以下の点を気をつけるといいと思います。
-
context
,describe
を正しく使って仕様書として読みやすくすること -
context
,describe
で謳っていることと、before
,subject
,it
内のテストコードの内容が一致すること/一致することがすぐわかること
上記を守って楽しくプログラミング!