Sometimes we need to classify the tests in a project and a possible solution to achieve this goal is to assign different categories to the tests.
Often we’re doing this to separate the execution of fast-running and long-running tests or to run a specific set of tests that is only applicable in special situations.
To run a specific set of categorized tests there are different options and in the following tutorial we’ll be covering two of them: by configuring the Maven Surefire Plug-in or by using a JUnit Test Suite and the JUnit annotations.
Dependencies
As you might have imagined, we’re in need of a testing framework here namely JUnit .. adding this one dependency to your pom.xml should be sufficient to run the following examples
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
JUnit Test Categories
Now we should add some test categories .. a test category is a simple marker interface – that means an empty interface. We’re adding two test categories here:
The firs one is used for slow running tests:
package com.hascode.tutorial.test.group;
/**
* Marker interface for fast-running tests.
*/
public interface FastRunningTests {}
The following one is for slow running tests:
package com.hascode.tutorial.test.group;
/**
* Marker interface for slow-running tests.
*/
public interface SlowRunningTests {}
Test with Categories assigned
Now that we’ve got test categories we should create some tests and assign the categories to them – either on class level or method level …
So this is our first test class and we’re assigning the category for fast running tests on class level
package com.hascode.tutorial.test;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.hascode.tutorial.test.group.FastRunningTests;
@Category({ FastRunningTests.class })
public class FirstTest {
@Test
public void testSth() throws Exception {
System.out.println("FirstTest.testSth run");
assertTrue(true);
}
@Test
public void testAnotherThing() throws Exception {
System.out.println("FirstTest.testAnotherThing run");
assertTrue(true);
}
}
And another test class with a mixed set of slow and fast categorized test methods assigned at method level
package com.hascode.tutorial.test;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.hascode.tutorial.test.group.FastRunningTests;
import com.hascode.tutorial.test.group.SlowRunningTests;
public class SecondTest {
@Test
@Category({ FastRunningTests.class, SlowRunningTests.class })
public void testSth() throws Exception {
System.out.println("SecondTest.testSth run");
assertTrue(true);
}
@Test
@Category({ SlowRunningTests.class })
public void testAnotherThing() throws Exception {
System.out.println("SecondTest.testAnotherThing run");
assertTrue(true);
}
}
Test Profiles in Maven
If you want to handle different test runs with different categories then one solution is to use maven profiles here.
We’re defining one maven profile for the fast running tests – this one is enabled by default – and another for the slow running tests.
<profiles>
<profile>
<id>fastTests</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>com.hascode.tutorial.test.group.FastRunningTests</groups>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>slowTests</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>com.hascode.tutorial.test.group.SlowRunningTests</groups>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Running with the default Profile
These profiles allow you to select which test categories you’d like to run … in the first example we’re running with the default profile “fastTest“.
$ mvn test
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Concurrency config is parallel='none', perCoreThreadCount=true, threadCount=2, useUnlimitedThreads=false
Running com.hascode.tutorial.test.SecondTest
SecondTest.testSth run
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec
Running com.hascode.tutorial.test.FirstTest
FirstTest.testSth run
FirstTest.testAnotherThing run
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
Running with a specific Profile
If you’d like to run a specific profile and the tests with the assigned category you may specify the profile using -PprofileName
$ mvn -Dtest=SlowRunningTestSuite -o test
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Concurrency config is parallel='none', perCoreThreadCount=true, threadCount=2, useUnlimitedThreads=false
Running com.hascode.tutorial.test.SecondTest
SecondTest.testSth run
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
Using a Test Suite
Another viable option is to create a classic test suite and assign the test categories affected in there using annotations.
package com.hascode.tutorial.test.suite;
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
import com.hascode.tutorial.test.FirstTest;
import com.hascode.tutorial.test.SecondTest;
import com.hascode.tutorial.test.group.FastRunningTests;
@RunWith(Categories.class)
@IncludeCategory(FastRunningTests.class)
@SuiteClasses({ FirstTest.class, SecondTest.class })
public class FastRunningTestSuite {}
package com.hascode.tutorial.test.suite;
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
import com.hascode.tutorial.test.FirstTest;
import com.hascode.tutorial.test.SecondTest;
import com.hascode.tutorial.test.group.SlowRunningTests;
@RunWith(Categories.class)
@IncludeCategory(SlowRunningTests.class)
@SuiteClasses({ FirstTest.class, SecondTest.class })
public class SlowRunningTestSuite {}
Tutorial Sources
Please feel free to download the tutorial sources from my GitHub repository, fork it there or clone it using Git:
git clone https://github.com/hascode/junit-category-selection.git