circleciとかでdb:resetしてからテストしてるんだけど、seedがある前提でテスト書くのは普通なのかな?(seedの使い方間違ってる気がしてきた)
— naichi (@naichilab) 2018年2月11日
twitterで説明するのは辛くなってきたのでqiitaで書いてみます。
テストに必要なデータは、fixtureで用意する
{project}/spec/factories/category.rb みたいなファイルに、fixtureを用意する。
FactoryGirl.define do
factory :category do
sequence(:name) { |n| "category#{n}" }
is_open true
end
end
ここでは、とりあえず普通のデータを作れるようになっていればOK。異常系のテストデータとかそんなややこしいことまでは書かない。
テストで使う
たとえばmodel specだと、 {project}/spec/models/category_spec.rb みたいなファイルに書く。
たとえばCategoryクラスに、そのカテゴリをWEBで見るURLを取得するurlメソッドがあったとすると。
RSpec.describe Category, type: :model do
context 'URL normal case' do
before do
let(:category_a) { create :category }
end
it 'returns url' do
expect(category_a.url).to eq Category::BASE_URL + URI.encode(category.name)
end
:
異常系とかのテストデータはこうやって用意する
RSpec.describe Category, type: :model do
context 'URL abnormal case' do
before do
let(:category_a) { create :category, name:'//<!-- -->' }
end
it 'URLに不適切な文字列が出力されないこと' do
expect(category_a.url).not_to include('!')
expect(category_a.url).not_to include('-')
expect(category_a.url).not_to include(' ')
end
:
こんな感じでテストできる。
fixtureには汎用的な例だけが書いてあって、テストに固有のデータ(異常系の文字列とか、境界の値とか)はspecファイルに書くのがポイント。こうしておくと、specファイルを見るだけでmodelやcontrollerの使い方をだいたい理解できるようになる。
seeds.rbは何に使うの?
よくあるのは、カテゴリやタグのデフォルトデータを入れておく。
Category.delete_all
Category.find_or_create_by!({
id: 1,
name: "ファストフード",
importance: 5,
})
Category.find_or_create_by!({
id: 2,
name: "喫茶店",
importance: 5,
})
こうしておくことで、立ち上げ後にカテゴリを一個一個管理画面から作らなくて済むようになる。
※ とはいえ、そんなまっさらなデータを用意しなきゃいけない場面なんてプロジェクト立ち上げのごく一時期で、本番運用が始まればseeds.rbなんて怖くて走らせられないので、seeds.rbはあまり顧みられなくなることが多い気がする.
で、新人さんが入ってきて環境立ち上げすると、seeds.rbがメンテされてなくて「あれ?」みたいなことになる😅
seeds.rbにテストデータを入れちゃだめな理由
本番に必要なデータが入ってるのだから、これでテストすれば楽なんじゃないか?という誘惑はわかるのですが。
テストに必要なデータは多種多様だし、テストはどんどん増えてくものだから、その全てのデータをseeds.rb一個にいれようとすると、いずれ破綻します。
(新しいテストのためにseeds.rbを編集したら既存のテストが通らない!みたいなことになります)
seeds.rbはそういう用途に使うファイルじゃないので、テストに必要なデータはfixtureに入れましょう。specテストに必要なデータは全部spec内で生成するので、テストのときにseeds.rbは使いません。