The Test With Fixtures
Lets take the classic example of an Order item, that has_one product. If you are testing to ensure that the correct total is computed. With fixtures, it might look like:
def test_total_should_return_price_times_quantity
assert_equal 33.00, order_items(:first).total
end
To see that this is valid, you would have to look in order_items.yml to find out the quantity for item :first is 3, then look in products.yml to find that the price is 11.00.
There have been a number of alternatives to fixtures proposed, including Jay Fields' idea of using mocks to avoid database access, which seems like going a bit too far for my tastes; and fixture scenarios, which only solve part of the problem. Here's what I do:
The Test Without Fixtures
First, I create a build method for each of my model objects. This method will create a valid object with reasonable default values, except as modified by a hash parameter. For simple objects with no associations, it looks like this:
def build_product(attrs = {})
Product.new({
:name => "Test Product",
:price => 10.00,
}.merge(attrs))
end
For more complex objects, the builder should create any reasonable associated objects or use those past in:
def build_order_item(attrs = {})
OrderItem.new({
:quantity => 1,
:product => build_product,
}.merge(attrs))
end
These builder methods I usually put in test_helper.rb, since they ussualy need to be called from multiple test files. With these in place, out total test becomes:
def test_total_should_return_price_times_quantity
order_item = build_order_item(
:quantity => 3,
:product => build_product(:price => 11))
assert_equal 33.00, order_item.total
end
This test doesn't touch the database, and all the details relevant to what is begin tested are in one place.