LoginSignup
3
3

More than 5 years have passed since last update.

factory_girl_railsで生成したオブジェクトを破壊的メソッドで変更する場合の注意点

Posted at

factory_girl_railsで生成したオブジェクトを破壊的メソッドで変更する場合の注意点

factory_girl_railsを使ってテストデータを生成し、
そのデータを直接変更した場合にはまったので紹介しておきます。

Factoryで生成したオブジェクトを破壊的メソッドを使って変更すると、
別のテストで再度生成する場合に、変更された値で生成されるということです。(つまりFactoryの型を破壊してしまうということ)

具体的な例で説明します。
一つのテストデータを使って、一部分だけ変更したデータを複数作成したい場合があります。
例えば、レポートNoだけをインクリメントして10件登録するような場合を考えます。

ベースとなるテストデータは次の通り。

test/factories/reports.rb
FactoryGirl.define do
  factory :report_test1, class: :Report do
    report_no 'R00001'
    title 'report title'
    content 'report content'
  end
end

テストコードは次の通り。
(レポートNo確認用のログも含めています)
レポートを10件生成して一覧のテストを行い、
レポートを1件生成して表示のテスト行う場合です。

test/controller/reports_controller_test.rb
require 'test_helper'

describe ReportsController do
  describe "index" do
    before do
      report_no = FactoryGirl.build(:report_test1).report_no
      10.times do
        report = FactoryGirl.build(:report_test1)
        report.report_no = report_no.succ! #破壊的メソッドでインクリメント
        puts "[index]report no:#{report.report_no}"
        report.save
      end
    end

    it "10件のデータを取得できる" do
      get :index
      assert_equal 10, assigns(:reports).count
    end
  end

  describe "show" do
    before do
      report = FactoryGirl.create(:report_test1)
      puts "[show]report no:#{report.report_no}"
    end

    it "指定したレポートを取得できる" do
      get :show, id: 1

      assert_equal 'R00001', assigns(:report).report_no
    end

  end
end

結果は次の通りです。
showのテストで登録した1件のレポートNoが期待した値と異なっていました。
indexのテストで更新したレポートNoが残った形となっています。

$ bundle exec rake test
Run options: --seed 59117

# Running tests:

[index]report no:R00002
[index]report no:R00003
[index]report no:R00004
[index]report no:R00005
[index]report no:R00006
[index]report no:R00007
[index]report no:R00008
[index]report no:R00009
[index]report no:R00010
[index]report no:R00011
.[show]report no:R00011 // ここはR00001を期待していた
F

Finished tests in 0.097491s, 20.5147 tests/s, 20.5147 assertions/s.

  1) Failure:
ReportsController::show#test_0001_指定したレポートを取得できる [/Users/xxx/test_app/test/controllers/reports_controller_test.rb:29]:
Expected: "R00001"
  Actual: "R00011"

2 tests, 2 assertions, 1 failures, 0 errors, 0 skips

Factoryのベースとなるデータは使い回されていると考えると納得できます。

そうとわかれば対策は次の通りです。
最初のレポートNoを取得する部分を変更します。

report_no = FactoryGirl.build(:report_test1).report_no.dup

これで期待した結果となりました。

$ be rake test
Run options: --seed 21061

# Running tests:

[index]report no:R00002
[index]report no:R00003
[index]report no:R00004
[index]report no:R00005
[index]report no:R00006
[index]report no:R00007
[index]report no:R00008
[index]report no:R00009
[index]report no:R00010
[index]report no:R00011
.[show]report no:R00001
.

Finished tests in 0.089792s, 22.2737 tests/s, 22.2737 assertions/s.

2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
3
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3