I'm generally OK with a loop in a test as long as there's only one occurrence of an assertion in the test. In other words, this is OK:
test "something" do
for item in @collection
assert_something item
end
end
But this is not:
test "something" do
for item in @collection
assert_something item
assert_something_else item
end
end
And these will make you hate yourself:
test "something" do
for item in @collection
assert_something item
if x == y
assert_something_else item
end
end
end
test "something" do
for item in @collection
assert_something item
end
for item in @collection
assert_something_else item
end
end
And the only time I would write a test this way is if the items in the collection vary from each other substantially, but there was some need to verify commonly shared behavior. For instance, you might have ten instances of different objects, but they all are supposed to respond to some message. So you verify that all instances can do the thing that the duck-typed method is supposed to do. But if you have a collection that always contains instances of Foo
, you're often better off just making an assertion about @collection.first
. The test executes faster, and you don't really gain much from repeating the assertion on all instances, and in most cases, you're much better off just testing item
in isolation from the rest of the collection anyway. If you're feeling particularly paranoid, this is generally OK:
test "items are all Foo" do
for item in @collection
assert_kind_of Foo, item, "Everything in @collection must be Foo."
end
end
test "something" do
assert_something @collection.first
end
The "something" test will fail anyways if you've got non-Foo
objects in the collection, but the preceding test makes it abundantly clear what the real problem is.
In a nutshell, avoid it, but if you've got a good reason to do it, then go ahead. And if it becomes a problem down the road, the test should still be simple enough that refactoring it into something less problematic is easy.