The quality of a software project is the desired aspect always. Programmers write code and they will do unit testing, block level testing, and sometimes integration testing too. But they will provide a few examples alone for the use cases. For example, if they are finding a number is prime or not, maybe they will provide some 2 to 3 different sets of numbers and confirm that the written code is working fine. But in practice, it is not the usual case. To overcome the above flaws, automated testing is required and it can be done via JUnit. In this tutorial let us see how to do that.
Example Project
Project Structure:
This is a maven-driven project. Hence let us see
pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 < modelVersion >4.0.0</ modelVersion > < groupId >com.gfg.examples</ groupId > < artifactId >NumberService</ artifactId > < packaging >jar</ packaging > < version >1.0-SNAPSHOT</ version > < properties > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < maven.compiler.source >1.8</ maven.compiler.source > < maven.compiler.target >1.8</ maven.compiler.target > < junit.version >5.3.1</ junit.version > < pitest.version >1.4.3</ pitest.version > </ properties > < dependencies > <!-- junit 5, unit test --> < dependency > < groupId >org.junit.jupiter</ groupId > < artifactId >junit-jupiter-engine</ artifactId > < version >${junit.version}</ version > < scope >test</ scope > </ dependency > </ dependencies > < build > < finalName >maven-mutation-testing</ finalName > < plugins > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-surefire-plugin</ artifactId > < version >3.0.0-M1</ version > </ plugin > < plugin > < groupId >org.pitest</ groupId > < artifactId >pitest-maven</ artifactId > < version >${pitest.version}</ version > < executions > < execution > < id >pit-report</ id > < phase >test</ phase > < goals > < goal >mutationCoverage</ goal > </ goals > </ execution > </ executions > <!-- Need this to support JUnit 5 --> < dependencies > < dependency > < groupId >org.pitest</ groupId > < artifactId >pitest-junit5-plugin</ artifactId > < version >0.8</ version > </ dependency > </ dependencies > < configuration > < targetClasses > < param >com.gfg.examples.*Calculator*</ param > < param >com.gfg.examples.*Stock*</ param > </ targetClasses > < targetTests > < param >com.gfg.examples.*</ param > </ targetTests > </ configuration > </ plugin > </ plugins > </ build > </ project > |
Now let us see the business logic file
CalculatorService.java
Java
public class CalculatorService { public boolean checkPositive( int inputNumber) { boolean isPositive = false ; // Lets include 0 as it is // neither positive nor negative if (inputNumber >= 0 ) { isPositive = true ; } return isPositive; } public boolean checkNegative( int inputNumber) { boolean isNegative = false ; // Lets include 0 as it is // neither positive nor negative if (inputNumber <= 0 ) { isNegative = true ; } return isNegative; } public boolean checkEvenNumber( int inputNumber) { boolean isEven = false ; if (Math.abs(inputNumber) % 2 == 0 ) { isEven = true ; } return isEven; } public boolean checkOddNumber( int inputNumber) { boolean isOdd = false ; if (Math.abs(inputNumber) % 2 == 1 ) { isOdd = true ; } return isOdd; } // Similarly we can write so many methods to check // whether is it divisible by 6, 9 etc., public boolean checkWhetherPrimeOrNot( int inputNumber) { boolean isPrime = true ; int checkingNumber = Math.abs(inputNumber) / 2 ; for ( int idx = 2 ; idx <= checkingNumber; idx++) { if (inputNumber % idx == 0 ) { isPrime = false ; // Once we get the satisfying condition, // we need to come out of the loop break ; } } return isPrime; } } |
TestCalculatorService.java
Java
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.junit.jupiter.api.Test; public class TestCalculatorService { @Test public void testForPositiveNumber() { CalculatorService calculatorService = new CalculatorService(); assertEquals( true , calculatorService.checkPositive( 10000 )); assertNotEquals( true , calculatorService.checkPositive(- 10001 )); // kill mutation #1 assertEquals( true , calculatorService.checkPositive( 0 )); } @Test public void testForNegativeNumber() { CalculatorService calculatorService = new CalculatorService(); assertEquals( true , calculatorService.checkNegative(- 210000 )); assertNotEquals( true , calculatorService.checkNegative( 210009 )); // kill mutation #1 assertEquals( true , calculatorService.checkNegative( 0 )); } @Test public void testForEvenNumber() { CalculatorService calculatorService = new CalculatorService(); assertEquals( true , calculatorService.checkEvenNumber( 410000 )); assertEquals( true , calculatorService.checkEvenNumber(- 221144 )); assertNotEquals( true , calculatorService.checkEvenNumber( 410001 )); assertNotEquals( true , calculatorService.checkEvenNumber(- 221149 )); } @Test public void testForOddNumber() { CalculatorService calculatorService = new CalculatorService(); assertEquals( true , calculatorService.checkOddNumber( 12345 )); assertEquals( true , calculatorService.checkOddNumber(- 232323 )); assertNotEquals( true , calculatorService.checkOddNumber( 12348 )); assertNotEquals( true , calculatorService.checkOddNumber(- 232316 )); } @Test public void testForPrimeNumber() { CalculatorService calculatorService = new CalculatorService(); // 12345 is not prime assertEquals( false , calculatorService.checkWhetherPrimeOrNot( 12345 )); // 232323 is not prime assertEquals( false , calculatorService.checkWhetherPrimeOrNot(- 232323 )); // 9839 is prime assertEquals( true , calculatorService.checkWhetherPrimeOrNot(- 9839 )); } } |
We can write our required business logic in the first java file (CalculatorService.java) and similarly its relevant JUnit test case checking in the second java file (TestCalculatorService.java). Always it is good to check for multiple scenarios in the test file. Then only our business logic will get stronger and when it is deployed in production, i.e. during the usage of the application, there are no issues observed. Hence always keep JUnit testing mandatory in any software project. As we have provided the dependency in pom.xml for JUNIT, they are all downloaded from maven central. We will get the option to run the file as a JUNIT test as shown below
Output:
In case there are any errors encountered, we will be getting errors as indicated below. Suppose, our code is as follows, then the last statement is incorrectly written. So either the business logic written way is wrong, or wrongly tested. On execution of the test case, we will come up with this error.
Java
@Test public void testForPrimeNumber() { CalculatorService calculatorService = new CalculatorService(); // 12345 is not prime assertEquals( false , calculatorService.checkWhetherPrimeOrNot( 12345 )); // 232323 is not prime assertEquals( false , calculatorService.checkWhetherPrimeOrNot(- 232323 )); // 9839 is prime, but we have written to get it as not prime. // Check for input number or else check for the assert part how it is // written assertEquals( false , calculatorService.checkWhetherPrimeOrNot(- 9839 )); } |
Conclusion
Hence writing JUnit provides quality software and it is a good asset to the software industry.