Em 24-04-2011 12:09, David Chelimsky escreveu:
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 ...

Yes, I know, I just wanted to make my point. This is not a real test case.

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.

Not exactly, only if the Rails API changes which I don't think it will happen for find in the near future.

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?

The problem with this approach is that I don't want Company.find(1, 2) to return Company.find(1), since it should return [Company.find(1), Company.find(2)]...

Actually, I was thinking about something like this:

company = mock_active_model(Company)
Company.find(company.id).should == company

I mean, whenever a mock for some ActiveModel or ActiveRecord instance is created, the class should also be stubbed to return that instance on find too. There are basically two find alternatives: find(id[, options]) and find(id1, id2...[, options]). These haven't changed as long as I can remember, so I think it would be safe to include something like that on rspec-rails.

Do you agree?

Best regards, Rodrigo.

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

Reply via email to