Wednesday, August 24, 2011

Organizing unit tests

I have been using a different approach to organizing the unit tests and this have turned out to be very effective. Worth sharing.

So if we have a class that looks like:
public class AccountService {
  public void getAllAccounts() { ... }
  public void createAccount() { ... }
  public void removeAccount() { ... }
}

For such a class we would traditionally have a unit test class called AccountServiceTest and all the test cases for all methods mentioned above. We would also have a bunch of global variables in the Test class and a setup (@Before) method.

My different approach involves creating a unit test class for each method rather than just one test class. So now we would have three classes:
public class AccountService_getAllAccounts_Test {}
public class AccountService_createAccount_Test {}
public class AccountService_removeAccount_Test {}

Generalizing it the unit test class name should be:
<<class under test>>_<<method under test>>_Test.java

Each class would have test cases for only the method referenced in the file name.

So how is this approach effective?

SRP - Single Responsibility Principle - is restored
In the traditional way the SRP principle is violated with the setup method as it is now common to all the test cases for all methods for the class under test. The setup has responsibilities to setup the objects and data for all the test methods for all methods in a class. Even the Test class has multiple responsibilities to test all methods in there. With the new approach every test class has responsibility to test only one single method under test.

"Look and Feel" of unit test cases
This is more of a perception thing but it works. Say if every method under test can have 5 unit test cases, in the above example having a single test case class means we already have 15 methods in there. When a developer looks at a single class with that had large number of methods with a single setup method that looked cryptic and they were less likely to update any unit test cases or even add more tests to them. When the classes were separated the "look and feel" of the test cases improved developers are now willing to and able to extend existing code base by adding new test cases.

What are the side effects of this approach?
  • Popular plugins like moreunit do not work anymore
  • Proliferation of Test classes may be something some developers may not like at first.

Let me know what you think !!!

3 comments:

  1. Interesting approach, Ayan! I have a question: doesn't this lead to more violations of DRY if one in turn is writing method-scoped setups/teardowns? (The alternative would be to go with an abstract class and you'd be back where you started regarding the SRP concern.)

    Also, I find "look and feel" can be largely addressed through better naming of test methods (rspec provides a good guide) especially if using an IDE's 'outline' view.

    ReplyDelete
  2. There could be a few more DRY violations in setting up the same mock method calls and the same mock data. However I found more comfort level in the team to live with with these DRY violations. Some of the mock data creation was extracted out into separate static test data classes. The repetition of mock methods calls was not a big issue then.

    And yes -- the look and feel can be addressed through better naming of test methods and this approach directs exactly towards that. By extracting out the name of class and method under test in the test class name the test method names are very more specific. These can in fact now follow the Given When Then structure more naturally.

    ReplyDelete
  3. In my opinion, there is almost no such thing as a "violation of DRY" in a test. If what you were hoping to get out of the tests is maintainability, then you're much better off with each test being comprehensible in a linear fashion. So go nuts and repeat yourself as often as you like, and hardcode often.

    ReplyDelete