JUnit 4 Test Suites
import org.junit.runners.Suite;
import org.junit.runner.RunWith;
@RunWith(Suite.class)
@Suite.SuiteClasses({TestClass1.class, TestClass2.class})
public class TestSuite {
//nothing
}
TestSuite Setup in jUnit 4
Here is what I have and it runs just fine.
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ TestSuite1.class, TestSuite2.class })
public class CompleteTestSuite {
@BeforeClass
public static void setUpClass() {
System.out.println("Master setup");
}
@AfterClass public static void tearDownClass() {
System.out.println("Master tearDown");
}
}
Here is my test suite 1 (do the same for test suite 2).
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(value = Suite.class)
@SuiteClasses(value = { TestCase1.class })
public class TestSuite1 {}
And here is my test class. Create both testcase1 and testcase2.
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestCase1 {
@BeforeClass
public static void setUpClass() {
System.out.println("TestCase1 setup");
}
@Test
public void test1() {
assertEquals(2 , 2);
}
}
you should have 5 classes
completesuite
suite1
suite2
test1
test2
and make sure you have Junit in your build path. This should run!
Here is the output
Master setup
TestCase1 setup
Master tearDown
How do you create nested TestSuites in JUnit 4.x?
The first problem is that Test3 uses @RunWith(Suite.class)
, but doesn't contain @Suite.SuiteClasses({Test3.class, .....})
. This produces an IntializationError: class 'Test3' must have a SuiteClasses annotation
. Since you aren't intending there to be any classes underneath Test3, this annotation should be removed.
The second problem of Exception: No runnable methods
is almost always due to forgetting to add @Test
to a test. You didn't put the tests in your sample, so I don't know if that's actually the case or not, but it's the most likely cause.
The following is a working version of your code that allows tests to be run from any class:
Test1.java
import org.junit.runner.*;
import org.junit.runners.*;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({Test2.class})
public class Test1 {
}
Test2.java
import org.junit.runner.*;
import org.junit.runners.*;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({Test3.class})
public class Test2 {
}
Test3.java
import static org.junit.Assert.*;
import org.junit.*;
public class Test3 {
@Test
public void testTrue(){
assertTrue(true);
}
}
As for whether or not there is a better way than to organize things, I guess it just depends on how you decide to create the classes. Since you can add suites to suites, as this demonstrates, you can create smaller chunks of suites that depend on everything, like a tree. For instance, what I generally do is:
AllTestSuite
TextParsingSuite
GuiSuite
SwingSuite
JavaFXSuite
FileIOSuite
A test is added to the most relevant suite. In the end, I don't think I have any suite with more than 10 test classes/suites or so. If I do, it's time to make a new sub-suite. In other words, there is no "huge list somewhere", just a lot of smaller lists that are combined together into another list in order to effectively make one big list.
I suppose you could use some tool to dynamically find all of the Java classes containing tests, but JUnit itself doesn't support this behavior (it only runs the tests you tell it to, which I personally think is a good thing).
How to get a collection of tests in a JUnit 4 test suite
After a bit of experimentation, I discovered the following solution:
SuiteClasses suiteClassesAnnotation = AllTests.class.getAnnotation(SuiteClasses.class);
if (suiteClassesAnnotation == null)
throw new NullPointerException("This class isn't annotated with @SuiteClasses");
Class<?>[] classesInSuite = suiteClassesAnnotation.value();
Basically, it gets the classes the same way that JUnit itself gets them: by looking into the annotation and determining which values are included within it.
The category solution provided by dkatzel is also a good option if you're ultimately wanting to filter these classes, but if you need a list of classes in a suite for some other purpose such as code analysis, this is the simplest and most direct way to do it.
How can I build a configurable JUnit4 test suite?
In Junit you can use categories. For example this suite will execute al test from the AllTestSuite annotated as integration:
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Categories.class)
@IncludeCategory(Integration.class)
@Suite.SuiteClasses ({AllTestsSuite.class} )
public class IntegrationTestSuite {}
You can also use @ExcludeCategory. This is usefull to remove slow tests. Categories classes are just plain old Java classes or interfaces. For example:
public interface Integration{}
public interface Performance{}
public interface Slow{}
public interface Database{}
You only need to anotate your tests acordingly:
@Category(Integration.class)
public class MyTest{
@Test
public void myTest__expectedResults(){
[...]
One test might have more than one category like this:
@Category({Integration.class,Database.class})
public class MyDAOTest{
For simplicity I usually create a Suite with all classes in the test folder using google toolbox:
import org.junit.runner.RunWith;
import com.googlecode.junittoolbox.ParallelSuite;
import com.googlecode.junittoolbox.SuiteClasses;
@RunWith(ParallelSuite.class)
@SuiteClasses({"**/**.class", //All classes
enter code here "!**/**Suite.class" }) //Excepts suites
public class AllTestsSuite {}
This works incluiding in AllTestSuite all classes in the same folder and subfolders even if they don't have the _Test sufix. But won't be able to see test that are not in the same folder or subfolders. junit-toolbox is available in Maven with:
<dependency>
<groupId>com.googlecode.junit-toolbox</groupId>
<artifactId>junit-toolbox</artifactId>
<version>2.2</version>
</dependency>
Now you only need to execute the Suite that suits your needs :)
UPDATE: In Spring there is the @IfProfileValue annotation that allows you to execute test conditionally like:
@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"})
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
For more information see Spring JUnit Testing Annotations
Running TestSuite in JUnit4 and Maven
I would assume that your test classes are not named based on the naming convention for test in relationship with maven-surefire-plugin
includes>
<include>**/*Test*.java</include>
<include>**/*Test.java</include>
<include>**/*TestCase.java</include>
</includes>
Apart from that you shouldn't use TestSuites, cause surefire-plugin will handle that already. So usually there is no need to suites to be defined separately.
Related Topics
Java Conditional Compilation: How to Prevent Code Chunks from Being Compiled
The Meaning of Noinitialcontextexception Error
Synchronizing on an Integer Value
Windows Shortcut (.Lnk) Parser in Java
Reverse Each Individual Word of "Hello World" String with Java
Can the Jvm Recover from an Outofmemoryerror Without a Restart
How to Add Unicode in Truetype0Font on PDFbox 2.0.0
Package Conflicts with Automatic Modules in Java 9
How to Keep a Scanner from Throwing Exceptions When the Wrong Type Is Entered
Java 1.6: Creating an Array of List<T>
Docker: Combine Multiple Images
How to Implement Dynamic Gui in Swing
Helper in Order to Copy Non Null Properties from Object to Another
Java.Util.Date Format Ssssss: If Not Microseconds What Are the Last 3 Digits
How to Decode JSON with Unknown Field Using Gson
Limiting the Number of Characters in a Jtextfield
Java Generics: Cannot Cast List<Subclass> to List<Superclass>
Java Spring Boot: How to Map My App Root ("/") to Index.Html