Unit Testing – How to Unit Test Method Returning a Collection Without Logic in Test

collectionslogicloopsunit testing

I am test-driving a method that is to generate a collection of data objects. I want to verify that the properties of the objects are being set correctly. Some of the properties will be set to the same thing; others will be set to a value which is dependent on their position in the collection. The natural way to do this seems to be with a loop. However, Roy Osherove strongly recommends against using logic in unit tests (Art of Unit Testing, 178). He says:

A test that contains logic is usually testing more than one thing at a time, which isn't recommended, because the test is less readable and more fragile. But test logic also adds complexity that may contain a hidden bug.

Tests should, as a general rule, be a series of method calls with no control flows, not even try-catch, and with assert calls.

However, I can't see anything wrong with my design (how else do you generate a list of data objects, some of whose values are depended on where in the sequence they are?—can't exactly generate and test them separately). Is there something non-test-friendly with my design? Or am being too rigidly devoted to Osherove's teaching? Or is there some secret unit test magic I don't know about that circumvents this problem? (I'm writing in C#/VS2010/NUnit, but looking for language-agnostic answers if possible.)

Best Answer

TL;DR:

  • Write the test
  • If the test does too much, the code may do too much too.
  • It may not be a unit test (but not a bad test).

The first thing for testing is about dogma being unhelpful. I enjoy reading The Way of Testivus which points out some issues with dogma in a lighthearted way.

Write the test that needs to be written.

If the the test needs to be written some way, write it that way. Attempting to force the test into some idealized test layout or not have it at all is not a good thing. Having a test today that tests it is better than having a "perfect" test some later day.

I will also point to the bit on the ugly test:

When the code is ugly, the tests may be ugly.

You don’t like to write ugly tests, but ugly code needs testing the most.

Don’t let ugly code stop you from writing tests, but let ugly code stop you from writing more of it.

These can be considered truisms to those who have been following for a long time... and they just become ingrained in the way of thinking and writing tests. For people that haven't been and are trying to get to that point, reminders can be helpful (I even find re-reading them helps me avoid getting locked into some dogma).


Do consider that when writing an ugly test, if the code it may be an indication that the code is trying to do too much too. If the code that you are testing is too complex to be properly exercised by writing a simple test, you might want to consider breaking the code into smaller parts that can be tested with the simpler tests. One should not write a unit test that does everything (it might not be a unit test then). Just as 'god objects' are bad, 'god unit tests' are bad too and should be indications to go back and look at the code again.

You should be able to exercise all the code with reasonable coverage through such simple tests. Tests that do more end to end testing that deal with larger questions ("I have this object, marshalled into xml, sent to the web service, through the rules, back out, and unmarshalled") is an excellent test - but it certainly isn't a unit test (and falls into the integration testing realm - even if it has mocked services that it calls and custom in memory databases to do the testing). It may still use the XUnit framework for testing, but the testing framework doesn't make it a unit test.

Related Topic