06 - Advanced JUnit options

6.1 JUnit parameterized test

6.2 JUnit execution procedure

6.3 Rules

6.4 Categories   

JUnit 4.x is simpler, richer, and easier to use than JUnit 3.x version and introduces more flexible initialization and cleanup, timeouts, parameterized test cases, rules and category concepts.

6.1 JUnit parameterized test

JUnit allows developers to use parameters in a test class. The test class can be marked as a parameterized test using the annotation:

@RunWith(Parameterized.class)

The test class must contain a static method annotated with @Parameters that generates and returns a Collection of Arrays. Each item in this collection is used as the parameters for the test method.

Instances are created for the cross product (binary operation of two arrays) of the test methods and the test data elements during running a parameterized test class.

The public constructor will store the values for each test. The number of elements in the constructor of the class must be equal to the number of the elements in each array provided by the method annotated with @Parameters. The test values and the class created for each parameter are passed via the constructor to the class.

The following example, contains a parameterized class. The method which calculates the means will be tested. 

package main.java.examples;

public class MyUtils {    
    public static double mean(int a, int b) {
        double sum = 0;
        sum = a+b;
        return sum / 2;
    }    
}

package test.java;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Collection;

import main.java.examples.MyUtils;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class MyParameterizedTest {
    private int number1;
    private int number2;
    private int expected;

     //parameters pass via this constructor
     public MyParameterizedTest(int number1, int number2, int expected) {
            this.number1 = number1;
            this.number2 = number2;
            this.expected = expected;
     }
     // creates the test data
     @Parameters(name = "{index}: mean(({0}+{1})/2)={2}")
     public static Collection<Object[]> data() {
     Object[][] data = new Object[][] {
                        { 4, 6, 5 }, 
                        { 2, 2, 2 }, 
                        { 8, 2, 5 }, 
                        { 1, 5, 3 } 
               };
        return Arrays.asList(data);
      }
        @Test
        public void test_mean() {    
            assertEquals(expected,MyUtils.mean(number1, number2),0.0001);
        }
}

The result in Eclipse is:

If we want to run the test from the command line we have to create the TestRunner class:

package test.java;

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class ParameterizedTestRunner {
    public static void main(String[] args) {
          Result result = JUnitCore.runClasses(MyParameterizedTest.class);
          for (Failure failure : result.getFailures()) {
             System.out.println(failure.toString());
          }
          System.out.println(result.wasSuccessful());
       }
}

If the workspace folder is C:\junit\junit_parameterized_test then:

C:\junit\junit_parameterized_test>javac -classpath "C:\junit\junit-4.11.jar";"C:\junit\junit-master\lib\hamcrest-core-1.3.jar"; MyUtils.java MyParameterizedTest.java ParameterizedTestRunner.java


C:\junit\junit_parameterized_test>java -classpath "C:\junit\junit-4.11.jar";"C:\junit\junit-master\lib\hamcrest-core-1.3.jar"; ParameterizedTestRunner

The result is:

6.2 JUnit execution procedure

The execution procedure of methods in JUnit is a concept that let developers specify which method is called first and which one after that.

We can create a java class file name JunitAnnotation.java in C:\junit\execution_procedure to test annotation: 

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 ExecutionProcedureJunit {

   //execute only once, in the starting 
   @BeforeClass
   public static void beforeClass() {
      System.out.println("in before class");
   }
   //execute only once, in the end
   @AfterClass
   public static void  afterClass() {
      System.out.println("in after class");
   }
   //execute for each test, before executing test
   @Before
   public void before() {
      System.out.println("in before");
   }    
   //execute for each test, after executing test
   @After
   public void after() {
      System.out.println("in after");
   }    
   //test case 1
   @Test
   public void testCase1() {
      System.out.println("in test case 1");
   }
   //test case 2
   @Test
   public void testCase2() {
      System.out.println("in test case 2");
   }
}

Create the java class TestRunner.java in C:\junit\execution_procedure to execute annotations

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(ExecutionProcedureJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
} 

Compile the Test case and Test Runner classes using javac

C:\junit\execution_procedure >javac -classpath "C:\junit\junit-4.11.jar";"C:\junit\junit-master\lib\hamcrest-core-1.3.jar";  ExecutionProcedureJunit.java TestRunnerExecutionProcedure.java

C:\junit\execution_procedure >java -classpath "C:\junit\junit-4.11.jar";"C:\junit\junit-master\lib\hamcrest-core-1.3.jar";  TestRunnerExecutionProcedure

The Test Runner will run test case defined in provided Test Case class.

Verify the output.

The result in Eclipse console is:

in before class

in before

in test case 1

in after

in before

in test case 2

in after

in after class

The output in command line is: 

First of all beforeClass() method execute only once.

Finally, the afterClass() method executes only once.

before() method executes for each test case but before executing the test case.

after() method executes for each test case but after the execution of test case

In between before() and after() each test case executes.

6.3 Rules

A Rule is a modification in how a test method or more test methods are run ore reported.

@Rule annotation implies that the class is implementing the interface TestRule.

@ClassRule annotation corresponds to the class-level TestRule.

Rules allow writing code to inspect a test before it is run, modify how and whether to run the test, inspect and modify the test results.

A rule implementation can intercept test method execution and alter the behaviour of these tests, or add cleanup work as it was done in @Before@After@BeforeClass and @AfterClass.

The concept of rules is similar to JUnitRunners but with the benefit of mixing multiple rules. When more Runners are to be combined it is recommended to use cases of rules.

This feature allows the test to be cleaner and powerful.

Some useful rules are already implemented in JUnit. The TemporaryFolderRule allows creation of files and folders that are guaranteed to be deleted when the test case finishes. (see more rules on

 https://github.com/junit-team/junit/wiki/Rules)

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class MyTestRule implements TestRule {
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                System.out.println("before");
                try {
                    base.evaluate();
                } finally {
                    System.out.println("after");
                }
            }
        };
    }
}

package test.java;

import org.junit.Rule;
import org.junit.Test;

public class MyTest {
    @Rule
    public MyTestRule myTestRule = new MyTestRule();

    @Test
    public void testValidity() throws Exception {
        System.out.println("test execution");
    }
}

The Eclipse output in Console after running the test is:

And in JUnit console:

This result proves that the rule interceptor is working as expected.

6.4 Categories

JUnit 4.8 introduced a new feature called Categories. These are implemented as classes or interfaces.

This makes possible to define custom category types like unit – integration – acceptance tests. To assign a test case or a method to one of those categories the Category annotation is provided.

Developers have the option to exclude or include groups or categories of tests.

For example, if we define two categories of: FastTests and SlowTests and use them as interfaces.

public interface FastTests { /* category marker */ }
public interface SlowTests { /* category marker */ }

public class A {
    @Category(SlowTests.class)
    @Test public void methodA() {}
}

@Category(FastTests.class})
public class B {
    @Test public void methodB() {}
}

@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@ExcludeCategory(FastTests.class)
@SuiteClasses({ A.class, B.class })
public class SlowTestSuite {}
  • annotation is used to label the test classes and test methods with one more category.

The methodA and class B are marked as belonging to one or more categories of test class. This include automatically all its test methods in such category.

@IncludeCategory(SlowTests.class) and @ExcludeCategory(FastTests.class) are specifying which test cases should be included or excluded when suite is execute.

Categories can be used with Maven or Gradle builds without defining particular suite classes (see

Category section of JUnit documentation).

Like us on Facebook