Mutation Tests - Ensure the quality of your code now

gabrielaugusto1996

Gabriel Augusto Morato dos Santos

Posted on October 14, 2022

Mutation Tests - Ensure the quality of your code now

Hello World, welcome to my article related to mutation testing.

Special thanks:

Before we start, I would like to thank my friend Paulo Ricardo for the encouragement of writing this article and being able to share my vision of this tool with the rest of you.

What is Mutation Testing anyway?

image

Pitest makes a mutation in your project, it allows you to guarantee a real margin of coverage within your tests by making a “copy” of the project and inserting errors to see if your tests will fail after the mutation. When the test fails the mutant is killed. If any mutant survives this means you need to do more unit tests, the live mutants serve as input to create more tests.

Okay, but how does this help me with the quality of my code?

image

Due to the classic rush that developers need to get into to deliver a particular project, testing is done more in order to increase code coverage, but this is not correct, testing comes with the objective of providing more quality that you are delivering to a client or consumer and also documenting so that another developer can better understand your code, later on you will understand where I want to go :)

What technologies will we use?

image

For this article, we will need to have the following technologies in our project:

  1. Java 8+: Java Programming Language in version 8+
  2. Junit 5: Test development framework
  3. Maven: Build automation tool
  4. Pitest: Tool to perform mutant tests
  5. Spring: programming framework

I will not go into too much into all the technologies used because it is not our purpose of this article.

Setting up our project:

image

In order for us to use pitest, we need to use Junit 4 or higher, but as mentioned earlier, we will use Junit5:

<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <version>1.7.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.7.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <version>5.7.1</version>
    <scope>test</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

It will also be necessary for us to add the pitest plugin to our project, which is the main objective of our article:

            <plugin>
                <groupId>org.pitest</groupId>
                <artifactId>pitest-maven</artifactId>
                <version>1.4.11</version>
                <dependencies>
                    <dependency>
                        <groupId>org.pitest</groupId>
                        <artifactId>pitest-junit5-plugin</artifactId>
                        <version>0.8</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <targetClasses>
                        <param>YourClassPackage.*</param>
                    </targetClasses>
                    <targetTests>
                        <param>YourTestPackage.*</param>
                    </targetTests>
                </configuration>
            </plugin>
Enter fullscreen mode Exit fullscreen mode

Note: There are other settings that you can set in the plugin according to your preference, such as excluding a certain class or package that will not be tested:

<excludedClasses>
 <param>PackageOfYourClasses.*</param>
 <param>PackageOfYourClasses.IamAClass</param>
</excludedClasses>
Enter fullscreen mode Exit fullscreen mode

I just hope you don't delete the entire project, ok? :D

Revealing the problems with testing for coverage only:

image

As mentioned earlier, due to some rush or even lack of knowledge, the developer usually does the test just for coverage or ends up forgetting to insert some important validation, so let's analyze the following scenario:

  • Inside our project we have a class called UserFactory

  • In our method we will receive as parameters a String(name) and an Integer(year)

  • After that we will make the instance of the User class and we will set the parameters received to their respective attributes

  • Soon after, we will return the user

public final class UserFactory {

    private UserFactory() {}

    public static User create(final String name, final Integer year) {
        final User user = new User();

        user.setName(name);
        user.setYear(year);

        return user;
    }
}
Enter fullscreen mode Exit fullscreen mode

Okay, after we understood the purpose of our method, let's go to our test class, UserFactoryTest:

class UserFactoryTest {

    @Test
    @DisplayName("Should return a User - When success")
    void create_User_WhenSuccess() {
        final Integer year = 10;
        final String name = "Dudu";

        final User user = UserFactory.create(name, year);

        Assertions.assertNotNull(user);
        Assertions.assertEquals(name, user.getName());
    }
}
Enter fullscreen mode Exit fullscreen mode

As we can see, we made the method call of our class and made the following checks:

  • We looked that the return object is not null
  • We verified that expected name* is equal to the name entered in user

Shall we check out our coverage?

Image description

But after all, in this simple example we had no problem, where was our mistake?

Exactly, we forgot to do the validation if the year attribute was set correctly, let's see what the Pitest has to say?

Getting more into the tool:

image

To run Pitest we can just execute following command:

mvn org.pitest:pitest-maven:mutationCoverage

Enter fullscreen mode Exit fullscreen mode

Or run the plugin directly in your IDE by clicking on the pitest:mutationCoverage option, the choice is yours :)

Captura de tela de 2021-03-16 23-41-57

If project is configured correctly, you will get the following results, when execution is complete:

Image description

As we can see above, the Pitest generated 5 mutations and with our test we managed to kill only 3, but don't worry, so that you have a more analytical view, the *Pitest * generates a report for you, so that we can access it, just follow the following path:

  • target
  • pit-reports
  • index.html

Image description

As we can see, Pitest took our line from user.setYear(year); and said that if we remove the call from that line, the result will be the same and we know this is not true, right? :)

So now we just go back to our test class and make the necessary changes.

Thank you guys:

image

Thanks to all of you for reading my article, as I said this was the first of many to come, so if you liked it or have a comment so you can be supporting and encouraging me I will be extremely grateful :)

Now I leave a special challenge for you to run Pitest on your project and tell me what was your reaction when you saw the result :D

Note: My first time was not very positive, but it helped me to have a higher quality in the projects :D

💖 💪 🙅 🚩
gabrielaugusto1996
Gabriel Augusto Morato dos Santos

Posted on October 14, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related