has_manyのクラスのインスタンスをRSpecで呼び出す

投稿者: Anonymous

RailsでCompanyクラスがPastDatahas_manyで持つ関係において
下記のようなコードを書いたのですが

describe Company do
  describe "exmaple test" do
    let(:company){ Company.create }
    context "fooが10の時" do
      let(:past_data){ company.past_data.build(foo: 10) }
      it "barは20" do
        expect(company.past_data_bar).to eq(20)
      end
    end
  end
end

app/models/company.rb

def past_data_bar
  past_data.bar
end

以下のように NoMethodErrorになってしまいます。

NoMethodError:
       undefined method `bar' for nil:NilClass

company.past_datanilになっているのが原因なのはわかるのですが、解決方法がわかりませんでした。

company.past_data.barと呼び出していますが、実際のコードではCompanyクラスの内部メソッドでpast_dataを呼び出しています。

RSpecでhas_manyの関係にあるクラスを呼び出しているメソッドのテストはどのように書けば良いのでしょうか?

解決

company.past_dataにすると、letで宣言したオブジェクトが呼ばれないので、expectの中はpast_dataだけにしてみてください。

describe Company do
  describe "exmaple test" do
    let(:company){ Company.create }
    context "fooが10の時" do
      let(:past_data){ company.past_data.build(foo: 10) }
      it "barは20" do
        expect(past_data.bar).to eq(20)
      end
    end
  end
end

EDIT:

コメントの内容を勘案するとこうなりそうです。

describe Company do
  describe "exmaple test" do
    let(:company){ Company.create }
    context "fooが10の時" do
      let!(:past_data){ company.past_data.build(foo: 10) }
      it "barは20" do
        expect(past_data_bar).to eq(20)
      end
    end
  end
end

letだとbeforeやitの中でpast_dataが呼び出されるまでletのブロックは実行されません。
let!にすると、テストの実行前に必ずブロックが呼び出されるようになります。

詳しくはこの記事を読んでみてください。

遅延評価される let と事前に実行される let!

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *