FactoryGirlを追加した

いつもの、ごみシリーズです。

今週土日は、自分の所属しているバドミントンクラブのHPの作成で終わってしまいました。 デザイン難しい。

さて、今回は前回 RspecでHTTPのリクエスト・レスポンスのテストを行った - takapi86のブログ で追加したテストに、テストデータを追加していきます。

こちらを参考に導入を行いました。

File: GETTING_STARTED — Documentation for factory_girl (4.8.0)

導入

  • Gemfilefactory_girl_railsを追加して、bundle installします。
group :test do
  gem 'factory_girl_rails'
end
  • factory_girlのテストデータを作成するコードを保管する場所として、spec/factories/ を作成しておきます。

ファイルを作成する

区モデル(ward)、町モデル(town)のFactoryGirlファイルを作成します。 ※ward、townは1:nの関係です。

詳しくは、

  • spec/factories/wards.rbを作成
FactoryGirl.define do
  factory :ward do # モデル名を指定
    sequence(:id)
    ward_code 16
    name '港北区'
  end
end
  • spec/factories/towns.rbを作成
FactoryGirl.define do
  factory :town do # モデル名を指定
    sequence(:id)
    ward_code 16
    initial_code 3
    town_code 1073
    name '篠原町'
  end
end

試してみる

  • test環境にコンソールで入ります。
RAILS_ENV=test bundle exec rails c

wardのデータを作ってみる

[1] pry(main)> ward = FactoryGirl.create(:ward)
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "wards" ("id", "ward_code", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["id", 1], ["ward_code", 16], ["name", "港北区"], ["created_at", 2017-03-26 14:57:30 UTC], ["updated_at", 2017-03-26 14:57:30 UTC]]
   (145.8ms)  commit transaction
=> #<Ward:0x00559a99c3ccb8
 id: 1,
 ward_code: 16,
 name: "港北区",
 created_at: Sun, 26 Mar 2017 14:57:30 UTC +00:00,
 updated_at: Sun, 26 Mar 2017 14:57:30 UTC +00:00>

townのデータを作ってみる

[2] pry(main)> FactoryGirl.create(:town, ward: ward)
   (0.1ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "towns" ("id", "ward_code", "initial_code", "town_code", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?)  [["id", 1], ["ward_code", 2], ["initial_code", 3], ["town_code", 1073], ["name", "篠原町"], ["created_at", 2017-03-26 14:59:00 UTC], ["updated_at", 2017-03-26 14:59:00 UTC]]
   (60.9ms)  commit transaction
=> #<Town:0x00559a9daa47f8
 id: 1,
 ward_code: 2,
 initial_code: 3,
 town_code: 1073,
 name: "篠原町",
 created_at: Sun, 26 Mar 2017 14:59:00 UTC +00:00,
 updated_at: Sun, 26 Mar 2017 14:59:00 UTC +00:00>

うまくいったっぽいです。 念の為、testのDBはクリアしておきます。

RAILS_ENV=test bundle exec rake db:migrate:reset

前回のテストに追加

require 'rails_helper'

RSpec.describe TownsController, type: :request, json: true do
  let(:town) { FactoryGirl.create(:town, ward: create(:ward)) }

  describe 'GET /towns/:name.json' do
    before do
      get URI.escape("/towns/#{town.name}.json")
    end

    it '200 OK を返す' do
      expect(response.status).to eq(200)
    end
  end
end

こちらもうまくいったようです。

ちなみに、ここではFactoryGirl.createと記載していますが、クラス名は、 spec_helper.rbの Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } のコメントを外し、以下のようにファイルを追加するか、そのままconfig.include FactoryGirl::Syntax::Methods と追記することで、省略できます。

# spec/support/factory_girl.rb
RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

ただ、このままでは2回目実行すると、以下のようなエラーが発生してしまうようです。

ActiveRecord::RecordNotUnique:
       SQLite3::ConstraintException: UNIQUE constraint failed: wards.id: INSERT INTO "wards" ("id", "ward_code", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)
     # ./spec/requests/towns_spec.rb:2:in `block (2 levels) in <top (required)>'
     # ./spec/requests/towns_spec.rb:7:in `block (3 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # SQLite3::ConstraintException:
     #   UNIQUE constraint failed: wards.id
     #   ./spec/requests/towns_spec.rb:2:in `block (2 levels) in <top (required)>'

どうやら、続けてテストする場合は、テスト後にテストしたデータを削除する処理を入れる必要があるようです。 こちらは、次回対応していきたいと思います。