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.

Reply via email to