Unit tests

Unit tests are a great underestimate tool. They allow you to have a good confidence on what the code does. Unit tests also permit easier refactoring, protect the application/framework against regression. It assists new developers to enter the code without fearing breaking any feature.

Making unit tests can also be fun, it is a nice mind game to target high code coverage. I will try to explain my vision about unit tests.

What is a unit test

Unit test is the lowest layer of tests for your application/framework. Unit tests should be automated and run with each of your builds. They need to be efficient and have no dependency in the order.

A unit test must be efficient

A unit tests need to be efficient. Since you want to execute unit tests with each of your builds, the tests need to run quickly. Remember developers are human, if it takes too much time they won’t run tests if it’s too slow. So you always need to pay attention to the build time of your application/process.

A unit test must work in isolation

Unit tests must have no dependency on other tests and must not impact other tests. This mean if your test uses singleton or change any state of the application/framework it needs to be reset to his original value.

JUnit @Before and @After help a lot make this cleanup, this w. Also some

A unit test, test one method at the time

A unit test must be very specific. It must test a single method at the time.

Why should I test a single method if I can test multiples at the same time ?

Testing a single method at the time has many pros. It is easier to debug. If a test suddenly fails, you have a small scope to look at.

Also it facilitates method and classes refactoring.

Refactoring method without breaking an existing functionality is easy. You will only need to run the unit test of the appropriate method and they should pass.

Refactoring classes will also be facilitated because the it won’t affect other tests than the one of your classes. This mean you will never have to refactor all your tests because you make a change in your core class.

Moreover testing a one single method at the time force you to have simple tests and help you keep simple and fast unit tests.

A unit test, test public method only

A unit test must test only public method. I insist on the public because private method does not need to be unit tested. Private method should be covered by the unit test of public methods.

But wait… you just said we should test one method at the time ?

You are right, but since private method can’t be invoked (in a conventional way) they do not need to be tested in other means than by calling the public method.

Testing only public/protected method will allow you to detect dead code. If you do not achieve to cover some part of private method then you may have found some useless code. According to Yagni principle this code need to be removed.

For example, in the following class the line between from 12 to 14 need to be removed since myPrivateMethod will never receive a null value. Even if in the future the method may receive null value.

Here an example of unit tests for the previous class

How to validate unit test quality

Unit test quality is hard to validate and most of the time displeasing to review.

So how can I be sure that all the work I have made in unit testing is worth it ?

First the unit test should fail fast with precise error message. If you have any test that fail and you can’t understand why it fails quickly, you may need to refactor the test to improve readability.

Then a test mustn’t fail randomly. If some of your tests fail sometime, you must investigate it quickly otherwise the test will be disabled and removed.

Also some tools can help you improve your test plan and test quality. Jacoco is a nice code coverage library. It allows you to check your code coverage and provide different metrics about your coverage (missed class, missed methods, missed blocks and missed line).

I personally really like the missed block analysis because it allows you to verify that you have well tested all corner case and not only the happy path. Because most of the problem I have seen with unit tests and code coverage is that developers and managers focus on line coverage and then developers will only test the happy path that contains most of the time a high percentage of the total line of code.

But be careful with code coverage, it seems a nice metric to say

Hey guys, 99% line of code of my application is tested !

Wrong, the code coverage shows you what code was touched by your test, it does not validate that you have done some validation on it. So don’t be overconfident because you have unit tests. 😉

For example, here a bad test for list:

And here a more relevant test but both have the same coverage

 

Another tool I recently discover and find it interesting is PI Test. This tool makes mutations on your code in order to validate the real impact of the code on your tests.

Unit tests must be isolated from each other, the order of test execution and the success or failure of the previous test shouldn’t impact others.

Why using unit test

Unit test improve code quality

Developing unit tests while coding force the developers to have another point of view on their own code. This new perceptive on the code allows easy and fast detection of the corner case, and force the developer to think about it. In the same way it force to think about null handling and exception handling which, in my opinion, are often underestimated.

Unit tests allow developers to make better code. Making unit tests while coding help the developer to have another point of view on their own code. It permits an easy and fast detection of badly handled corner case. Also it forces you to think about null handling, exception handling, etc. It allows to detect architecture problems. Indeed, a code that is hard to test show weakness in your code. Too many duplications in your testing code show you may be able to have a more generic code.

Unit test protect you again regression

Unit test goal is not only to prove that the function is working as expected, it is also to be sure that any future change won’t break the function tested.

It is really appreciated for a dev to have a high confidence on the application/framework unit tests. It permits to make refactoring and code modification with a limited fear or breaking any other functionality of the application. It means that any dev, even new on the project  can quickly make change on the code without breaking anything.

What to avoid in unit tests

Remember why you are using unit test and it will help you detect when you are not doing a unit test. For example, when you are testing a flow instead of a single method.

Also it is important not to modify your code to match the test. In other words, the test needs to adapt itself to the code without changes. It does not mean that when you are creating your test you can’t make any refactor in your code. It means that for example you won’t change the modifier because you want to access some private variable in your code. In some case you may want to but for those rare cases I would recommend using reflection to access this kind of information.

Finally, the initialization code provides you some hint. Having complex initialization code or lots of mock means that you may be testing a too large part of our application, or that your method does too many things or that you have an important architecture issue.

 

In conclusion, I will strongly recommend any developer to create unit tests for any project they are doing. It will help them to do better code, and will provide more confidence in the product that you will deliver.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *