Unit testing with Java , Maven and JUnit

What is Unit testing?

Unit testing is a way to test your units(i.e parts) of your program. Usually unit tests should include not only positive scenarios but also negative scenarios that can occur in your piece of code. Examples are exceptions, error, negative results like that.

Is it really important?
YES!
But most of the developers are not taking unit testing seriously, thinking it is a waste of time.

If you are thinking in that way, then you will certainly waste lot of time doing manual testing with different set of data/ scenarios to test your piece of code.

Every time , when there is a change, you will end up missing some steps(lazyness) and  it could  introduce new bugs when it is getting tested in IT(Integration testing) environment.

So, you be patient and put some time to write test cases, cover all the possible scenarios( positive and negative).

So next time when you change something in your code, it will break in unit testing, then you can easily fix and avoid bugs being popped up in IT.

Most importantly you are running all the testing scenarios which you could possibly miss when manually unit testing your code.(manually unit testing your code is NOT preferable).

What is Junit?

JUnit is a testing framework for writing test cases and test suites(set of test cases) to test your program unit by unit.

We will see how can we write and execute unit test cases in java using maven and junit.

Creating java project using maven:

Make sure you have java and maven installed in your system. You can run ‘mvn -version’ to check ,if the maven is installed. You want to install maven please check this post Install maven in linux .

Assuming we have created a project using maven, please check this post on How to create java project using maven.

You can run the following mvn command to create a simple project:

mvn archetype:generate -DgroupId=com.mksiva.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

It creates a project with default maven structure.

If you look at the generated pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mksiva.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

The JUnit is included by default. so you can use whatever version you want. I am going to use 4.10.

Writing Unit test cases and actual methods.

Writing failed test cases first then write our real methods to make it success. This particular method is called ‘TDD’ Test Driven Development.

We want to develop a method which will return addition of two numbers, if the inputs are not proper( null), then will throw our own exception, called AdditionProgramException.(custom exception), usually when you try to do some operation with null or improper input, you will get ‘NullPointerException’ or Exception but for our example purpose, we throw our own exception.

We have 2 classed created App.java, AppTest.java.

mvn_folder

Writing test case first:
The add method is not there, so we will go and create a new method add() in our App.java

unittest_error

we have added now a method.

App.java

package com.mksiva.app;

/**
* App
*
*/
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
}

/**
*
* @param aNumber
* @param aSecondNumber
* @return int addition result
*/
public int add(int aNumber, int aSecondNumber) {
int result = 0;
return result;
}
}

AppTest.java:

/**
* Testing addition
* /
@Test
public void testAdd() {
int number1 = 3;
int number2 = 3;
int theExpectedResult = 6;
int theActualResult = myTestingApp.add(number1, number2);
assertEquals(theExpectedResult, theActualResult);
}

Now we have written a test case and going to run it.

In terminal or command line, go to the directory of the project and run:

mvn clean test

you will see:

T E S T S
-------------------------------------------------------
Running com.mksiva.app.AppTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.065 sec <<< FAILURE! - in com.mksiva.app.AppTest
testAdd(com.mksiva.app.AppTest)  Time elapsed: 0.011 sec  <<< FAILURE!
java.lang.AssertionError: expected:<6> but was:<0>
at org.junit.Assert.fail(Assert.java:93)
at org.junit.Assert.failNotEquals(Assert.java:647)
at org.junit.Assert.assertEquals(Assert.java:128)
at org.junit.Assert.assertEquals(Assert.java:472)
at org.junit.Assert.assertEquals(Assert.java:456)
at com.mksiva.app.AppTest.testAdd(AppTest.java:47)
Results :
Failed tests:
AppTest.testAdd:47 expected:<6> but was:<0>
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE

Carefully look at the error message, expected result was 6 but actual is 0. So our add() is not returning correct value. So now we have to fix it.

We will change App.java as follows:

public int add(int aNumber, int aSecondNumber) throws AdditionProgramException {
int result = 0;
result = aNumber + aSecondNumber;
return result;
}

re-run mvn clean test in terminal:

The message is now as follows;

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.mksiva.app.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.106 sec - in com.mksiva.app.AppTest
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.048 s

We will add Exception handling now. And finally our App.java is fully implemented.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mksiva.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

App.java

package com.mksiva.app;
/**
* App
*
*/
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
}
/**
*
* @param aNumber
* @param aSecondNumber
* @return int addition result
* @throws AdditionProgramException
*/
public Integer add(Integer aNumber, Integer aSecondNumber) throws AdditionProgramException {
Integer result = 0;
if(aNumber == null || aSecondNumber == null){
throw new AdditionProgramException("Null param passed.");
}
try {
result = aNumber + aSecondNumber;
} catch (Exception e) {
throw new AdditionProgramException(e);
}
return result;
}
}

AppTest.java

package com.mksiva.app;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
/**
* Unit test for simple App.
*/
public class AppTest{
@Mock
App myTestingApp;
/**
* This will be called before any test executions.
*/
@Before
public void startUp(){
myTestingApp = new App();
}
/**
* This will be called after all the test cases are executed.
* So any clean up or freeing up operation should be done here.
*/
@After
public void cleanUp(){
myTestingApp = null;
}
/**
* Testing addition
* @throws AdditionProgramException
*/
@Test
public void testAdd() throws AdditionProgramException {
int number1 = 3;
int number2 = 3;
int theExpectedResult = 6;
int theActualResult = myTestingApp.add(number1, number2);
assertEquals(theExpectedResult, theActualResult);
}
@Test
public void testAddWithNull() throws AdditionProgramException {
Integer number1 = null;
Integer number2 = 3;
try {
myTestingApp.add(number1, number2);
} catch (AdditionProgramException e) {
assertEquals("Null param passed.", e.getMessage());
}
}
}

Now the test cases are executed and we have also covered positive and a negative testing scenarios.

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.mksiva.app.AppTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.131 sec - in com.mksiva.app.AppTest

Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.355 s

In Eclipse: Right click the AppTest.java –> run as –> Junit

eclipse_testrun2

The test results in eclipse:

 

testresult

 

Happy coding!.

Leave a Reply

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