DEV Community

Discussion on: How to improve Java Unit Testing Skills to a more advanced level?

Collapse
martinhaeusler profile image
Martin Häusler

There are some principles when writing tests in general. They're so very basic it seems almost stupid, but I find that I constantly have to remind myself of them in order not to get dragged away:

  1. Test the interface, not the implementation. Otherwise you'll just keep updating tests over and over again. Your implementation details can change, and WILL change in a long-running project. This also entails that you should test some of the cases which seem trivial. A trivial case today may be tomorrow's edge case after the implementation has changed. An untested trivial case today may crash your production app tomorrow. When your feature takes numeric inputs, always check positive, negative and zero inputs. For strings, try the empty string as well, include spaces, or some crazy UTF-8 characters if that's a requirement. For any sorts of collections, try the empty collection, the one-element-collection, and a bigger collection. Basically, you'll want to cover the equivalence classes of input parameters as good as possible. Parameterized tests can help to do this in a quick fashion.
  2. A test without an assertion is (almost) worthless. Smoke tests (which just checks if a command executes without throwing an exception) have their place, but in general you should always include assertions in your tests. Assertions can become pretty complex, depending on the degrees of freedom your test allows. There are various assertion frameworks out there to make this job a little easier, check those out (e.g. Assert4J, Hamcrest Matchers, Strikt for Kotlin users). Sometimes, writing assertions can clash with principle #1, it takes some practice and a good amount of judgment to get this right.
  3. A test that cannot fail is (almost) worthless. Imagine you're testing an age filter function that returns all users above the age of 18. In your test, if you don't feed it a user which is below that age, and then you verify that all returned users are indeed 18 or above, the test literally cannot fail, because you didn't provide it any input data where failure is possible.

Testing really is something that takes practice. The more tests you write, the better you'll become. Just make sure you get the basics straight. Frameworks (JUnit is totally fine, but get a good assertion library) and best practices can get you started, but you'll need to work for that "gut feeling" what to test on your own. It will come in time.

Collapse
zaerald profile image
Zaerald Author

Agreed on all the principles, and I want to take action to improve my testing skills.

Testing really is something that takes practice. The more tests you write, the better you'll become.

Do you have a recommendation for my next steps? A practical step to efficiently practice? What I currently do is look for open source projects and read on how they test but it feels like it's a passive thing to do, so I want to explore different paths I can take to actively practice and if I failed to create a test for something, I can look and see some solution.

Collapse
khmarbaise profile image
Karl Heinz Marbaise

I can recommend to try some code katas or very simple things like write a fraction class and try to use tests to implement it. It's very helpful and see how testing and implementing works in combination. Yeah it sounds useless to write such a class...but it helps practicing writing tests etc. because the problem domain is (more or less) simple....

Another level of going is to follow the principles of Kent Beck (read the book and try to write the previously mentioned Fraction class by using the TDD principles and of course practice, practice, practice....

Thread Thread
zaerald profile image
Zaerald Author

Awesome! Will try out those code katas 💪