John Bachir
John Bachir

Reputation: 22751

How do I test the behavior inside an ActiveRecord creation block?

How can I test code like this with rspec?

Foo.create! do |foo|
  foo.description = "thing"
end

I don't want to test of the object was created -- I want to test if the right methods were invoked with the right objects. Equivalent to testing this:

Foo.create!(description: "thing")

with this:

Foo.should_receive(:create!).with(description: "thing")

Upvotes: 4

Views: 143

Answers (3)

Damir Zekić
Damir Zekić

Reputation: 15950

Here's a combination approach that merges the best from @antiqe's and @Fitzsimmons' answers. It is significantly more verbose though.

The idea is to mock Foo.create in a way that behaves more like AR::Base.create. Frist, we define a helper class:

class Creator
  def initialize(stub)
    @stub = stub
  end

  def create(attributes={}, &blk)
    attributes.each do |attr, value|
      @stub.public_send("#{attr}=", value)
    end

    blk.call @stub if blk

    @stub
  end
end

And then we can use it in our specs:

it "sets the description" do
  f = stub_model(Foo)
  stub_const("Foo", Creator.new(f))

  Something.method_to_test

  f.description.should == "thing"
end

You could also use FactoryGirl.build_stubbed instead of stub_model. You can't, however, use mock_model, mock or double since you would have the same problem again.

Now your spec will pass for any of the following code snippets:

Foo.create(description: "thing")

Foo.create do |foo|
  foo.descrption = "thing"
end

foo = Foo.create
foo.descrption = "thing"

Feedback is appreciated!

Upvotes: 0

Fitzsimmons
Fitzsimmons

Reputation: 1591

Is this what you're after?

it "sets the description" do
  f = double
  Foo.should_receive(:create!).and_yield(f)
  f.should_receive(:description=).with("thing")

  Something.method_to_test
end

Upvotes: 1

antiqe
antiqe

Reputation: 1124

Foo.count.should == 1
Foo.first.description.should == 'thing'

Upvotes: 0

Related Questions