It seems that not that many developers migrating to JUnit 4 are aware of the replacement for the old way of building suites--using the static suite() method and the junit.framework.TestSuite class--I decided to blog a simple example for Google's indexing hamsters to grab hold of.
Here we go:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestCalculatorAddition.class,
TestCalculatorSubtraction.class,
TestCalculatorMultiplication.class,
TestCalculatorDivision.class
})
public class CalculatorSuite {
// the class remains completely empty,
// being used only as a holder for the above annotations
}
The above class is a simple placeholder for the suite annotations, not containing any other functionality as such. The key is in the @RunWith annotation, which tells the JUnit 4 test runner to use the org.junit.runners.Suite class for running this particular class. The @Suite annotation, on the other hand, tells the Suite runner which test classes to include in this suite and in which order.
I hope this helps folks out there since it doesn't seem to be documented too well in junit.org.
I love most of what's changed in JUnit 4 but I do have to say that I kind of agree with you on the syntax being a bit clunky.
Personally, I would've preferred having an alternative enabling the building of a test suite dynamically. Something like this:
@Suite
public class MySuite {
public static Test suite() {
// do it the old way
}
}
...where there's the old suite() method and the class is annotated with @TestSuite (mainly to help tool developers).
You'll have to pose the question to the JUnit developer list, though, to get the answer you're looking for...
Mark,
You can simply create a main method that invokes the JUnit API as follows:
public class MainForEmma {
public static void main(String[] args) {
JUnitCore.runClasses(new Class[] { MyTestSuite.class });
}
}
${testSrc} - is the top level test directory
${testDir} - is the directory where the classes you want to run are
<target name="runTests" description="run the junit tests">
<junit outputtoformatters="false" showoutput="no" fork="on" haltonfailure="no" printsummary="yes">
<formatter type="plain" usefile="false"/>
<classpath refid="classPath"/>
<batchtest>
<fileset dir="${testSrc}">
<include name="${testDir}/**/*Test.java/"/>
</fileset>
</batchtest>
</junit>
</target>
Did I understand correctly that you don't actually have a suite but rather multiple test classes that you collect from the file system for execution?
If this is the case, how do you run those tests in your IDE?
hi, thanks for the reply. i have several test classes to test, my Struts-Actions. i'm using <junit> and <junitreport> elements in Ant to test them and to generate the reports in HTML format. up to this is fine. the problem is i'm using <batchtest /> in <junit/> which is executing the test classes in alphabet sequence. and not in the desired sequence. to avoid that i'm using <test /> element in the <junit/>, which follows the desired sequence, but the problem is i need to mention more than 30 tags in <junit/> which is more adequate. when i tried to run the test classes from java with JUnitCore api, it is executing in the desired sequence. so my need is, i need to run the test cases from ant in some sequence. is there any format for that or is there any tag that executes the TestSuite.
Afroz,
I don't know of a way to do that in JUnit 4. In fact, I don't even know that I would want such an ability. Why? Because the fact that you want to execute only some tests from a given test class is an indicator of that test class being too big and incoherent. A design smell. Instead, you should consider splitting your test class into two or more.
What I usually do is I run the single test case in Eclipse by just right-clicking it from the JUnit runner and selecting "Run" (or "Debug" if I'm having a bad day ;).
I'm not sure how to do this from the command line, though. I mean, Ant (look for "run-single-test") and Maven have means of running a single test class but I'm not aware of a way to run a single test method with them.
You can add @BeforeClass and @AfterClass methods to your suite class and have them coordinate the system properties.
For example:
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( { ExampleTest.class, AnotherExampleTest.class })
public class MySuite {
public static final String PROPERTY_NAME = "whatever";
private static String previousValue;
@BeforeClass
public static void setUp() throws Exception {
previousValue = System.getProperty(PROPERTY_NAME);
System.setProperty(PROPERTY_NAME, "value for this suite");
}
@AfterClass
public static void after() throws Exception {
if (previousValue != null) {
System.setProperty(PROPERTY_NAME, previousValue);
previousValue = null;
}
}
}
@RunWith(Suite.class)
@SuiteClasses( { SomeTestSuite.class, AnotherTestSuite.class })
public class CompositeSuite {
}
I also have a problem with nested test suites. My hierarchy is:
test suite A |-test suite B | |-test case 1 |-test suite C |-test case 2test suite A contains:
@SuiteClasses( { B.class, C.class })
test suite B contains:
@SuiteClasses( { 1.class })
test suite C contains:
@SuiteClasses( { 2.class })
but when I run test suite A, the test methods of 1 and 2 will shown directly under A, and my hierarchy is lost.
What am I doing wrong? I am using NetBeans 6.0.1
Thanks, Oli
I understand how to make these JUnit 4 suites, now, but the problem is I don't want to have to explicitly put in the class names under @Suite.SuiteClasses().
I'm running my tests from Eclipse, and I want a suite class that creates a list dynamically. Is that even possible?
We're mixing JUnit 3 and JUnit 4 tests, but the old method of getting all the tests only picks up the JUnit3 tests. I'd love something that uses the new system.
I'd want something like this:
@RunWith(Suite.class)
@Suite.SuiteClasses(
getClassesInPackage()
)
public class PackageSuite {}
public class ShowAppreciation
{
public static void main(String[] args)
{
for (int i = 10; i<1000000; i++)
{
System.out.println("Thank you Lasse!");
}
}
}
public static Test suite() {
TestSuite suite= new TestSuite();
suite.addTest(new MoneyTest("testMoneyEquals"));
suite.addTest(new MoneyTest("testSimpleAdd"));
return suite;
}
I just want add some specific methods into a suite(), not the whole class, how could I do that?
You extract those test methods into a separate class...
Out of curiosity, what differentiates the tests that you want in your suite from the rest of the tests in that class?
I am reading Pragmatic Unit Testing in Java with Junit, it suggests to put part of test cases in suite(), but leave those time-consuming ones in a high level class which contains all tests.
Then by default only test contained in suite() run, and those "big" tests only run when we invoke the high level test.
Unfortunately this book only talks about junit 3.
Maybe it is not a good way to arrange test cases?
public class TestSingleMethod{
public static void main (String [] args )
{
JUnitCore junitcore = new JUnitCore();
junitcore.addListener (new TextListener());
junitcore.run(Request.method(TestClass.class, "method1"));
}
}
... will execute method 'method1' of class 'TestClass' (Junit 4.4)
package junittest;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import org.junit.Test;
import org.junit.internal.TextListener;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
public class TestSingleMethod
{
public static void main (String [] args )
{
JUnitCore junitcore = new JUnitCore();
try {
junitcore.addListener (new TextListener(new PrintStream (new FileOutputStream("testresult.txt"))));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
junitcore.run(Request.method(TestSingleMethod.class, "test1"));
}
@Test
public void test1 ()
{
System.out.println("test1");
ArrayList <Object> emptyList = new ArrayList <Object> ();
// Results in an error!
Object o = emptyList.get(0);
}
@Test
public void test2 ()
{
System.out.println("test1");
}
}
I made my example above a bit more detailed. Copy it, execute it and you will see, that test1 ist executed and its junit-testouput is written to the file "testresult.txt". However you will also see, that test2 is NOT executed by junit. I hope the short example will be of some help. (Env: jre1.5.0_12, eclipse 3.3, junit 4.4)








As with so many of these JUnit4 additions I'm struggling to see the advantage of this. It seems to be just replacing one clunky syntax with another.</p.
Do you have any suggestion of why (or when) it might be better to use this than the old suite method approach?