26 Apr 2014

Junit Best Practices

  • Advance

In the new project that I'm working now, the client asked me about if I could define a set of rules to make all the developers goes in the same direction, when they starting to write unitary test.

Using my experience as developer, and reading others blogs in internet related to best practices, I found an entry in a blog that represent that main idea I always had when I think in unitary test.

Using that blog as a starting point, but giving my personal touch, I defined a set of minimun rules to follow for every developer at time to write Junit test.

  • Explanation

  • TEST ONLY ONE CODE UNIT AT A TIME

When we try to test a unit of code, this unit can have multiple use cases. We should always test each use case in separate test case. For example, if we are writing test case for a function which is supposed to take two parameters and should return a value after doing some processing, then different use cases might be:

1. First parameter can be null. It should throw Invalid parameter exception.
2. Second parameter can be null. It should throw Invalid parameter exception.
3. Both can be null. It should throw Invalid parameter exception.
4. Finally, test the valid output of function. It should return valid pre-determined output.

This helps when you do some code changes or do refactoring then to test that functionality has not broken, running the test cases should be enough. Also, if you change any behaviour then you need to change single or least number of test cases.


  • MAKE EACH TEST INDEPENDENT TO ALL THE OTHERS


Do not make chain of unit test cases. It will prevent you to identify the root cause of test case failures and you will have to debug the code. Also, it creates dependency, means if you have to change one test case then you need to make changes in multiple test cases unnecessarily.


  • MOCK OUT ALL EXTERNAL SERVICES AND STATE

Otherwise, behaviour in those external services overlaps multiple tests, and state data means that different unit tests can influence each other’s outcome.
We have to be sure each test resets the relevant statics to a known state before it runs. We have to try avoiding dependences between tests and systems. And the order of the @Test methods does not be affected by a concrete order of execution.

You can use a lot of frameworks related to Mocking and with a clear integration with Junit. In internet you can find examples and best practices about how to Mock Services. At the end, the decision to select one or another framework is up to you.

  • NAME YOUR UNIT TESTS CLEARLY AND CONSISTENTLY

This is the most important point to keep remember and keep following. We must name our test cases on what they actually do and test. Test case naming convention which uses class names and method names for test cases name is never a good idea. Every time you change the method name or class name, you will end up updating a lot of test cases as well.
But, if our test cases names are logical i.e. based on operations then you will need almost no modification because most possibly application logic will remain same.
E.g. Test case names should be like (EmployeeTest is our Junit class):

1) EmployeeTest.create_NullId_ShouldThrowException

2) EmployeeTest.create_NegativeId_ShouldThrowException

3) EmployeeTest.create_DuplicateId_ShouldThrowException

4) EmployeeTest.create_ValidId_ShouldPass


  • AIM FOR EACH UNIT TEST METHOD TO PERFORM EXACTLY ONE ASSERTION

We should try to test only one thing in one test case. Do not test multiple things using assertions in single test case. This way, if some test case fails, you know exactly what went wrong.


  • CREATE UNIT TESTS THAT TARGET EXCEPTIONS

If some of your test cases, which expect the exceptions to be thrown from application, use “expected” attribute like this. Try avoiding catching exception in catch block and using fail/ or asset method to conclude the test.


  • DO NOT PRINT ANYTHING OUT IN UNIT TESTS

If you are correctly following all the guidelines, then you will never need to add any print statement in your test cases. If you feel like having one, revisit your test case(s).

  • Conclusions

We could include more rules to define our set of best practices when we develop junit test. My opinion about junit is not use junit as way to make functional testing, or to detect regressions, but always is good to define a minimum set of best practices. At the end, you should write your unitary test for your needs thinking in the best way to do that.

2 comments:

  1. Al final, si se hace bien, tienes al final mogollón de horas trabajadas en los tests, pero es que te da una tranquilidad, cuando tienes servidores de integración continua como jenkins y test automatizados. Buen post, me ha gustado y me apunto mas de una.

    ReplyDelete
  2. Gracias por tus comentarios!

    ReplyDelete