Eric Schmitt wrote:
>
> Marnen,
>
> I'm fairly new to unit testing and TDD,
I've been doing test-first development as long as I've been doing Rails
development, nearly 3 years. (Whether that means that I too am new to
unit testing is left as an exercise for the student.)
? but I think I understand the
> concept of what they're talking about here. The point is that if you are
> writing to the database during unit tests, you're actually testing the
> database adapter and abstraction layer, in this case: ActiveRecord, and
> not the logic that you have written.
That is commonly believed, but the situation is IMHO not that
open-and-shut. Read on.
> ActiveRecord, has been tested
> extensively, it would be redundant to test it again. By removing the
> database from the testing, you can focus on testing your business
> logic...
Not always. Often, removing the DB from testing makes it *harder* to
focus on testing the logic.
Some examples may be helpful here. Of course, it's asinine for me to do
User.create! :name => 'John'
User.find_by_name('John').should_not be_nil
as that would indeed be testing ActiveRecord. But consider
class Sandwich
def make_blt
Ingredient.create(:name => 'bacon')
Ingredient.create(:name => 'lettuce')
Ingredient.create(:name => 'tomato')
end
end
I think it is entirely reasonable to test this with
describe Sandwich
describe 'make_blt'
it "should create bacon, lettuce, and tomato" do
Sandwich.make_blt
['bacon', 'lettuce', 'tomato'].each do |name|
Ingredient.find_by_name(name).should_not be_nil
end
end
end
end
because this is not testing ActiveRecord; rather, it's testing that I
made the proper *calls* to ActiveRecord.
To be sure, in this case, I could just as easily do
Ingredient.should_receive(:create).with(:name => 'bacon'), but that's
only possible because the method is so simple, and to my mind it's a
little smelly anyway: since the method being tested should be treated as
a black box, I'd rather verify the final state than chase all the method
calls that got us there. And the only way to verify the final state is
to have something tracking that state -- like, oh, say, a DB.
> and you have the side benefit of it being quicker, which is
> essential for TDD to be a practical way to develop software.
An in-memory DB has similar benefits while not discarding state.
> I think
> what you're describing is considered to be functional testing or
> integration test, not unit testing.
The test I wrote above would certainly be considered a unit test.
[...]
> This is one of the *rare* times when I think Ruby got it wrong when
> compared with other languages, most other more mature languages Java,
> C++, etc.. provide tools to avoid hitting the database during unit
> testing for just this reason.
This is a Rails and ActiveRecord issue, not a Ruby one.
> I think Rails, and Ruby in general is
> heading in this direction too. The next generation of ORM databases like
> DataMapper have this sort of thing built in.
DataMapper is an ORM, not an "ORM database". In what respect does
DataMapper's testing differ here? (I've never used DataMapper, though
it certainly looks interesting.)
> Hope this helps!
Only by tending to confirm that some of the argument here is fallacious
(unless Avdi has a better one).
>
> Cheers,
> Eric
Best,
--
Marnen Laibow-Koser
http://www.marnen.org
[email protected]
--
Posted via http://www.ruby-forum.com/.
--
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.