Outside the Java commmunity, Java is often regarded as an old and verbose language. Though I love writing Java code, I kind of have to agree with this. New features are implemented slowly and looked upon by the language designers with thorough suspicion. For example, support for multi-line strings has been tried multiple times before Java got official support. If we are talking about verbosity, the Java language needs quite some characters to write a simple function. As I am specializing in functional programming in Java this year, I struggled a lot with this. Read along how I tackled this a little.
One of the first topics you will encounter when studying functional programming will probably be currying. For an imperative programmer not used to mathematical notations, chances are you will find the concept hard to grasp. Then let this be the day you will remember as the day you completely understood currying!
The time is right. Your work is done. The last letter of your Java code has been written. You let the IDE compile the code and a new running version of your app is ready to be released. You’ve done this a thousands times, there’s nothing new on the horizon. The question what lies beneath, what happens under the hood, has never occurred to you. Until now!
You might have heard about Mutation Testing before. In the last 5 or 6 years it’s been a reasonably hot (“warm”?) topic to discuss in blogs and dev talks. So what is the added value over code coverage with just Unit Testing? Even if you could pride yourself with over 90% line and branch coverage, that coverage means nothing apart from that unit tests are touching production code. It says nothing about how well that code is tested, it doesn’t care whether any asserts exist in your tests. Imagine an engineer that tests a power drill he designed on a sheet of paper, and declaring that it does exactly what it was designed for: drilling holes. It’s obvious that this test is meaningless for a power drill that is meant to be used on wood, steel or stone.
Mutation tests aim to expose tests that cover the lines they’re meant to cover but are insufficient in testing the intent of the code. The idea behind this is fairly simple: introduce “mutants” in the code that is being tested, and check whether the unit tests that cover these mutants still succeed or start to fail. If a test still succeeds, that means the test falls short of verifying the complete intent of the code!
So what is a “mutant” in this case?
Most of the time, it’s as simple as an operator
+, -, &&, || etc., that is “mutated” into a different one.
In this way, a mutation testing framework helps to identify code that is not tested sufficiently and identifies weak tests that still succeed when mutants are introduced.
If this is something you consider to be a valuable addition to your project, consider trying out Mutation Testing by following the guide below.
In this blog post, I walk through the steps of configuring and using the mutation testing framework PIT for a Java codebase and explain how to integrate it with the code quality inspection platform SonarQube.
Although Java has always been awesome, Java 8 has brought the language several features the language was in dire need of. Apart from the long-awaited improved DateTime-API and the introduction of Optionals, Java 8 finally gave behaviour the attention it deserves by incorporating (a form of) functional programming into the language using lambdas.