Grouping JUnit tests
Asked Answered
O

7

53

Is there any way to group tests in JUnit, so that I can run only some groups?

Or is it possible to annotate some tests and then globally disable them?

I'm using JUnit 4, I can't use TestNG.

edit: @RunWith and @SuiteClasses works great. But is it possible to annotate like this only some tests in test class? Or do I have to annotate whole test class?

Octavus answered 3/5, 2009 at 14:2 Comment(3)
Related: https://mcmap.net/q/183648/-junit-4-test-suites/…Madgemadhouse
@RunWith and @SuiteClasses is not great at all, look at stackoverflow.com/questions/18894951Abbevillian
IMHO, the second answer should be the accepted answer - official grouping support since junit 4.8Charo
F
14

Do you want to group tests inside a test class or do you want to group test classes? I am going to assume the latter.

It depends on how you are running your tests. If you run them by Maven, it is possible to specify exactly what tests you want to include. See the Maven surefire documentation for this.

More generally, though, what I do is that I have a tree of test suites. A test suite in JUnit 4 looks something like:

 @RunWith(Suite.class)
 @SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})
 public class UnitTestsSuite {
 }

So, maybe I have a FunctionTestsSuite and a UnitTestsSuite, and then an AllTestsSuite which includes the other two. If you run them in Eclipse you get a very nice hierarchical view.

The problem with this approach is that it's kind of tedious if you want to slice tests in more than one different way. But it's still possible (you can for example have one set of suites that slice based on module, then another slicing on the type of test).

Frankish answered 3/5, 2009 at 14:27 Comment(2)
Had to use syntax: @SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})Blomquist
@MatthewHegarty thanks, but please next time if you noticed a typo esp on the code itself, do not hesitate to do an edit. PLEASE don't post it as comment (as comment can get buried by influx of other comments) Its very unhelpful to the community, really. Thanks!Odessa
W
82

JUnit 4.8 supports grouping:

public interface SlowTests {}
public interface IntegrationTests extends SlowTests {}
public interface PerformanceTests extends SlowTests {}

And then...

public class AccountTest {

    @Test
    @Category(IntegrationTests.class)
    public void thisTestWillTakeSomeTime() {
        ...
    }

    @Test
    @Category(IntegrationTests.class)
    public void thisTestWillTakeEvenLonger() {
        ...
    }

    @Test
    public void thisOneIsRealFast() {
        ...
    }
}

And lastly,

@RunWith(Categories.class)
@ExcludeCategory(SlowTests.class)
@SuiteClasses( { AccountTest.class, ClientTest.class })
public class UnitTestSuite {}

Taken from here: https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0

Also, Arquillian itself supports grouping: https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java

Walz answered 29/8, 2011 at 23:59 Comment(3)
link broken weblogs.java.net/blog/johnsmart/archive/2010/04/25/…Coopt
this is impracticle to enumerate test classes with @SuiteClasses. must be smth to scan test classes by package or anything else.Orvilleorwell
For package-based grouping, you can simply use the package name or path with a wildcard. Anyway, we now have JUnit 5, and that one does grouping using custom @Tag-based annotations.Zackzackariah
F
14

Do you want to group tests inside a test class or do you want to group test classes? I am going to assume the latter.

It depends on how you are running your tests. If you run them by Maven, it is possible to specify exactly what tests you want to include. See the Maven surefire documentation for this.

More generally, though, what I do is that I have a tree of test suites. A test suite in JUnit 4 looks something like:

 @RunWith(Suite.class)
 @SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})
 public class UnitTestsSuite {
 }

So, maybe I have a FunctionTestsSuite and a UnitTestsSuite, and then an AllTestsSuite which includes the other two. If you run them in Eclipse you get a very nice hierarchical view.

The problem with this approach is that it's kind of tedious if you want to slice tests in more than one different way. But it's still possible (you can for example have one set of suites that slice based on module, then another slicing on the type of test).

Frankish answered 3/5, 2009 at 14:27 Comment(2)
Had to use syntax: @SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})Blomquist
@MatthewHegarty thanks, but please next time if you noticed a typo esp on the code itself, do not hesitate to do an edit. PLEASE don't post it as comment (as comment can get buried by influx of other comments) Its very unhelpful to the community, really. Thanks!Odessa
E
11

To handle the globally disabling them, JUnit (4.5+) has two ways One is to use the new method assumeThat. If you put that in the @BeforeClass (or the @Before) of a test class, and if the condition fails, it will ignore the test. In the condition you can put a system property or something else that can be globally set on or off.

The other alternative is to create a custom runner which understands the global property and delegates to the appropriate runner. This approach is a lot more brittle (since the JUnit4 internal runners are unstable and can be changed from release to release), but it has the advantage of being able to be inherited down a class hierarchy and be overridden in a subclass. It is also the only realistic way to do this if you have to support legacy JUnit38 classes.

Here is some code to do the custom Runner. Regarding what getAppropriateRunnerForClass might do, the way I implemented it was to have a separate annotation that tells the custom runner what to run with. The only alternative was some very brittle copy paste from the JUnit code.

private class CustomRunner implements Runner
 private Runner runner;

    public CustomRunner(Class<?> klass, RunnerBuilder builder) throws Throwable {
        if (!isRunCustomTests()) {
            runner = new IgnoredClassRunner(klass);
        } else {
            runner = getAppropriateRunnerForClass(klass, builder);
    }

    public Description getDescription() {
        return runner.getDescription();
    }

    public void run(RunNotifier notifier) {
        runner.run(notifier);
    }
}

EDIT: The @RunWith tag only works for a whole class. One way to work around that limiation is to move the test methods into a static inner class and annotate that. That way you have the advantage of the annotation with the organization of the class. But, doing that won't help with any @Before or @BeforeClass tags, you will have to recreate those in the inner class. It can call the outer class's method, but it would have to have its own method as a hook.

Electroacoustics answered 3/5, 2009 at 15:9 Comment(0)
W
8

In JUnit 5 you can declare @Tag for filtering tests, either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4

From the javadoc :

tags are used to filter which tests are executed for a given test plan. For example, a development team may tag tests with values such as "fast", "slow", "ci-server", etc. and then supply a list of tags to be used for the current test plan, potentially dependent on the current environment.

For example you could declare a test class with a "slow" @Tag that will be inherited for all methods and override it for some methods if required :

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("slow") 
public class FooTest{

   // 
   @Test
   void loadManyThings(){ 
        ...
   }

   @Test
   void loadManyManyThings(){ 
        ...
   }


   @Test
   @Tag("fast")
   void loadFewThings(){ 
        ...
   }

}

You could apply the same logic for other test classes.
In this way test classes (and methods too) belongs to a specific tag.

As a good practice instead of copying and pasting @Tag("fast") and @Tag("slow") throughout the test classes, you can create custom composed annotations.
For example :

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.junit.jupiter.api.Tag;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("slow")
public @interface Slow {
}

and use it as :

@Test
@Slow
void slowProcessing(){ 
    ...
}   

To enable or disable test marked with a specific tag during the text execution you can rely on the maven-surefire-plugin documentation :

To include tags or tag expressions, use groups.

To exclude tags or tag expressions, use either excludedGroups.

Just configure in your pom.xml the plugin according to your requirement (example of the doc) :

 <build>
     <plugins>
         ...
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <version>2.22.0</version>
             <configuration>
                 <groups>acceptance | !feature-a</groups>
                 <excludedGroups>integration, regression</excludedGroups>
             </configuration>
         </plugin>
     </plugins> 
</build> 

For information the test goal documentation is not updated.

Walloon answered 12/8, 2018 at 15:13 Comment(0)
M
4

Try JUnit Test Groups. From documentation :

@TestGroup("integration")
public class MyIntegrationTest {
   @ClassRule
   public static TestGroupRule rule = new TestGroupRule();

   ...
}
  • Execute a simple test group: -Dtestgroup=integration
  • Execute multiple test groups: -Dtestgroup=group1,group2
  • Execute all test groups: -Dtestgroup=all
Megasporophyll answered 24/12, 2015 at 2:23 Comment(0)
P
2

You can create test Suite objects that contain groups of tests. Alternatively, your IDE (like Eclipse) may have support for running all the tests contained in a given package.

Phonetic answered 3/5, 2009 at 14:25 Comment(0)
T
0

You can Use Test Suite(http://qaautomated.blogspot.in/2016/09/junit-test-suits-and-test-execution.html) or you can Junit Categories(http://qaautomated.blogspot.in/2016/09/junit-categories.html) for grouping your test cases effectively.

Tedious answered 14/9, 2016 at 5:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.