How to run JUnit tests by category in Maven?

JavaMavenJunitCategoriesMaven Surefire-Plugin

Java Problem Overview


Using JUnit 4.8 and the new @Category annotations, is there a way to choose a subset of categories to run with Maven's Surefire plugin?

For example I have:

@Test
public void a() {
}

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

And I'd like to run all non-slow tests as in: (note that the -Dtest.categories was made up by me...).

mvn test -Dtest.categories=!SlowTests // run non-slow tests
mvn test -Dtest.categories=SlowTests // run only slow tests
mvn test -Dtest.categories=SlowTests,FastTests // run only slow tests and fast tests
mvn test // run all tests, including non-categorized

So the point is that I don't want to have to create test suites (Maven just picks up all unit tests in the project which is very convenient) and I'd like Maven to be able to pick the tests by category. I think I just made up the -Dtest.categories, so I was wondering if there's a similar facility I can use?

Java Solutions


Solution 1 - Java

Maven has since been updated and can use categories.

An example from the Surefire documentation:

<plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.11</version>
      <configuration>
        <groups>com.mycompany.SlowTests</groups>
      </configuration>
</plugin>

This will run any class with the annotation @Category(com.mycompany.SlowTests.class)

Solution 2 - Java

Based on this blog post - and simplifying - add this to your pom.xml:

<profiles>
	<profile>
		<id>SlowTests</id>
		<properties>
			<testcase.groups>com.example.SlowTests</testcase.groups>
		</properties>
	</profile>
	<profile>
		<id>FastTests</id>
		<properties>
			<testcase.groups>com.example.FastTests</testcase.groups>
		</properties>
	</profile>
</profiles>

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-surefire-plugin</artifactId>
			<version>2.13</version>
			<dependencies>
				<dependency>
					<groupId>org.apache.maven.surefire</groupId>
					<artifactId>surefire-junit47</artifactId>
					<version>2.13</version>
				</dependency>
			</dependencies>
			<configuration>
				<groups>${testcase.groups}</groups>
			</configuration>
		</plugin>
	</plugins>
</build>

then at the command line

mvn install -P SlowTests
mvn install -P FastTests
mvn install -P FastTests,SlowTests

Solution 3 - Java

I had a similar case where I want to run all test EXCEPT a given category (for instance, because I have hundreds of legacy uncategorized tests, and I can't / don't want to modify each of them)

The maven surefire plugin allows to exclude categories, for instance:

<profiles>
    <profile>
        <id>NonSlowTests</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>my.category.SlowTest</excludedGroups>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Solution 4 - Java

You can use

mvn test -Dgroups="com.myapp.FastTests, com.myapp.SlowTests"

But ensure that you configure properly the maven surefire plugin

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-junit47</artifactId>
      <version>2.12.2</version>
    </dependency>
  </dependencies>
</plugin>

See docs in: https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html

Solution 5 - Java

I lost lot of time on this error "groups/excludedGroups require TestNG or JUnit48+ on project test classpath" because I thought I was using a bad version of junit, or a bad version of the surefire plugin, or a combination that does not fit.

It was none of that: in my project I had a "config" module that was built before the module I wanted to test. This module had no junit dependency -> it had no junit on the classpath...

This mistake may help others...

Solution 6 - Java

Not exactly the same thing but using surefire plugin, test classes can be chosen based on file name. You are not using Junit Categories though.

An example for running just DAO tests.

<executions>
  <execution>
     <id>test-dao</id>
        <phase>test</phase>
          <goals>
	         <goal>test</goal>
  		</goals>
          <configuration>
	         <excludes>
	         	<exclude>none</exclude>
		 	</excludes>
			<includes>					
		    	<include>**/com/proy/core/dao/**/*Test.java</include>
			</includes>
		</configuration>
  </execution>

http://maven.apache.org/plugins/maven-surefire-plugin/examples/inclusion-exclusion.html

Solution 7 - Java

I was having issue running test with categories ex: @Category(com.mycompany.SlowTests.class) when running the test via mvn test -Dgroups=com.mycompany.SlowTests.class

I discovered that tests in a classes without the word Test in their name would not run. After adding the word Test to the class the the tests in the class ran.

Solution 8 - Java

For the use-case where you want to ignore certain tests by default and then conditionally run all tests from the command line, this setup will work on JUnit 4.9.

First create the marker interface:

public interface IntegrationTest {}

Annotate tests to be excluded:

@Category(IntegrationTest.class)
public class MyIntegrationTest() {}

Add plugins and profiles to pom.xml:

<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <!-- Read JUnit categories to be excluded from Maven property -->
    <configuration>
      <excludedGroups>${test.excluded.groups}</excludedGroups>
    </configuration>
  </plugin>
</plugins>
  
<profiles>
  <profile>
    <id>Default</id>
    <!-- Set profile to be active by default -->
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
      <test.excluded.groups>com.example.IntegrationTest</test.excluded.groups>
    </properties>
  </profile>
  <profile>
    <id>AllTest</id>
    <!-- Set groups property to blank value which will match nothing -->
    <properties>
      <test.excluded.groups></test.excluded.groups>
    </properties>
  </profile>
</profiles>

When running tests as usual from command line, integration test will be excluded:

mvn test

All tests including integration tests can be activated with the corresponding profile:

mvn test -P AllTest

Solution 9 - Java

Junit 5 allows you to use the @Tag annotation. More info about that here: https://www.baeldung.com/junit-filtering-tests

I find it looks a little cleaner:

@Tag("SlowTests")
@Test
public void b() {
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRanView Question on Stackoverflow
Solution 1 - JavadmcnelisView Answer on Stackoverflow
Solution 2 - JavaMark ButlerView Answer on Stackoverflow
Solution 3 - JavaJoelView Answer on Stackoverflow
Solution 4 - JavapauclsView Answer on Stackoverflow
Solution 5 - JavaRemyView Answer on Stackoverflow
Solution 6 - JavaJesus BenitoView Answer on Stackoverflow
Solution 7 - JavamelofeloView Answer on Stackoverflow
Solution 8 - JavalarsView Answer on Stackoverflow
Solution 9 - Javauser952342View Answer on Stackoverflow