JUnit – Basics

Junit is desinged to be a unit testing framework for java. Junit is not necassary to do unit testing, you could write your own code. JUint provides a set of common tools that is required to write tests. Before moving further lets see what unit testing actually is. Basic idea behind unit testing is to take the smallest unit of code and test it by itself. In java  its a class or a method. If you are testing a more than a single class or having webservice/database calls, it still be a good test but not a unit test. Its more of a integration test , behaviour test etc. JUnit could be used for other types of testing as well. In fact other testing frameworks were build on top of Junit. Here we will first see some of the basic concepts of JUnit.

The first question arises, is where should the test be located? Typical, unit tests are created in a separate source folder to keep the test code separate from the real code. We could have a separate project also (Then we have to refer the source project into it). Here we are going to have a maven project with our code to be tested in the main folder and the unit test cases for it in the test folder, just as the default maven configuration are. So we created a simple maven project with following pom


<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mynotes.testing</groupId>
<artifactId>junit-demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>junit-demo1</name>
<description>Demo project for Junit</description>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<verbose>true</verbose>
<source>1.8</source>
<target>1.8</target>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
</plugins>
</build>
</project>

To keep things simple we just have one dependency of junit and set maven java compiler to java 8. Lets create a simple MathUtils class with a isEven method for which we will be writing test cases.


package com.mynotes.testing;

public class MathUtils {

public boolean isEven(String number) {
int x = Integer.parseInt(number);
if (x % 2 == 0) {
return true;
}
return false;
}
}

Now lets create another class in the test folder that will have unit test cases for this class. Following will be our project structure.

You can name your file anything but its a good practice to have the test file name similar to the class its going to test.

In order to create a Junit test case we first need to create a test method. To create a test method the :

  • method has to be public
  • its return type is void
  • It has a @Test annotaion above it.

MathUtilsTest.java


package com.mynotes.testing;

import org.junit.Test;
import static org.junit.Assert.*;

public class MathUtilsTest {

@Test
public void checkIsEvenWithValidNumberString() {
MathUtils aMathUtils=new MathUtils();
assertEquals("Testing with valid number string 222 ",true,aMathUtils.isEven("222"));
}

}

Above we created a test method checkIsEvenWithValidNumberString. The name of the method although not important but should be descriptive. In the method we used a static import method assertEquals. assertEquals is a overloaded method with many type/number of arguments that could be passed in it. I used a the options of 3 arguments where the 1st arg is a message on what we are testing. The second argument is whats the expected result and the 3rd argument is the actual test invocation. Right click on the class and run as Junit test.

Lets write another test case where we passed in a number string with a trailing space (say we expect the code to handle front/trailing spaces) and run. Adding following method in MathUtilsTest


@Test
public void checkIsEvenWithInvalidNumberString() {
MathUtils aMathUtils=new MathUtils();
assertEquals("Testing with valid number string 33 ",false,aMathUtils.isEven("33 "));
}

Apart from @Test there are other common Junit annotations that could be used

@Before

Executed before each test. It is used to prepare the test environment (e.g., read input data, initialize the class).

@After

Executed after each test. It is used to cleanup the test environment (e.g., delete temporary data, restore defaults). It can also save memory by cleaning up expensive memory structures.

@BeforeClass

Executed once, before the start of all tests. It is used to perform time intensive activities, for example, to connect to a database. Methods marked with this annotation need to be defined as static to work with JUnit.

@AfterClass

Executed once, after all tests have been finished. It is used to perform clean-up activities, for example, to disconnect from a database. Methods annotated with this annotation need to be defined as static to work with JUnit.

@Ignore or @Ignore("Why disabled")

Marks that the test should be disabled. This is useful when the underlying code has been changed and the test case has not yet been adapted. Or if the execution time of this test is too long to be included. It is best practice to provide the optional description, why the test is disabled.

@Test (expected = Exception.class)

Fails if the method does not throw the named exception.

@Test(timeout=100)

Fails if the method takes longer than 100 milliseconds.

Lets use some of them to give you an idea
Changing MathUtilsTest.java
</div>
<div class="sect2">package com.mynotes.testing;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;

public class MathUtilsTest {

@BeforeClass
public static void beforeClass(){
System.out.println("### BEFORE CLASS ###");
}

@Before
public void beforeEachTest(){
System.out.println("### BEFORE EACH TEST ###");
}

@Test
public void checkIsEvenWithValidNumberString() {
MathUtils aMathUtils=new MathUtils();
assertEquals("Testing with valid number string 222 ",true,aMathUtils.isEven("222"));
}

@Test
@Ignore
public void checkIsEvenWithInvalidNumberString() {
MathUtils aMathUtils=new MathUtils();
assertEquals("Testing with valid number string 33 ",false,aMathUtils.isEven("33 "));
}

@Test(expected=NumberFormatException.class)
public void checkIsEvenWithInvalidString() {
MathUtils aMathUtils=new MathUtils();
assertEquals("Testing with valid number string qq ",true,aMathUtils.isEven("qq"));
}

@After
public void afterEachMethod(){
System.out.println("### AFTER EACH TEST ###");
}

@AfterClass
public static void afterClass(){
System.out.println("### AFTER CLASS ###");
}

}</div>
<div class="sect2">
As you can see from output that 1 test got skipped because of @Ignore and from the console output you can see the behaviour of other annotations.
Now, since we used maven to uild our project, it will run these test cases for us before installing anything.
Lets run mvn clean install in our project.
This way we will be sure whether our code is correct or not.
%d bloggers like this: