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