On Apr 24, 2011, at 9:29 AM, Rodrigo Rosenfeld Rosas wrote:

> I've started a fresh rails app with Employee belongs_to Company.
> 
> Here is the spec:
> 
> describe Employee do
>  example "stub should work with find(id)" do
>    company = mock_model Company
>    Company.stub!(:find).with(company.id).and_return company
>    employee = Employee.new company_id: company.id
>    employee.company.should == company
>  end
> end

This ^^ is specifying Rails' behavior. There is a rather large test suite that 
does this already, so I'd recommend avoiding this sort of example in a model 
spec. Use-case specifics aside ...

> And here is the result:
> 
> Failures:
> 
>  1) Employee stub should work with find(id)
>     Failure/Error: employee.company.should == company
> <Company(id: integer, name: string, created_at: datetime, updated_at: 
> datetime) (class)> received :find with unexpected arguments
>         expected: (1001)
>              got: (1001, {:conditions=>nil})
> 
> Writing any of the following is not elegant:
> 
>  Company.stub!(:find).with(company.id, conditions: nil).and_return company
> or
>  Company.stub!(:find).with{|id, *args| id == company.id }.and_return company 
> # find could be called like Company.find(1, 2, 3) which should return an 
> array instead
> or
>  Company.stub!(:find).with{|id, *args| id == company.id && (args.size == 0 || 
> (args.size == 1 && args[0].is_a?(Hash)) }.and_return company
> 
> So, it would be great to add some syntax to rspec-rails like:
> 
>   Company.stub!(:find).with_id(company.id).and_return company
> 
> or
> 
>   Company.stub_find_with!(company.id).and_return company
> 
> I'm not sure yet what changes would be better, but the current implementation 
> makes it very hard to read specs like this that are so common when mocking 
> models.
> 
> What do you think?

Totally agree that this _should_ be easy. The problem with this approach is 
that it would add a dependency from rspec-rails on Rails' internals. That means 
that if/when the internals change, rspec-rails would break.

What about a more generalized `with` method that only constrains the first n 
arguments?

  Company.stub(:find).with_args_including(company.id).and_return company

This would work with find(company.id) or find(company.id, anything_else), but 
not find(anything_else, company.id). This doesn't guarantee solving the 
problem, but it reduces the risk of future breakage because the likelihood of 
active record changing that first argument to find is very small.

Thoughts?
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to