JUnit is the most famous unit testing framework for JAVA. It was created by Eric Gamma and Kent Beck.
With tap4j it is possible to generate TAP output for JUnit tests.
There are 2 possible ways to achieve the integration between tap4j and JUnit. One is creating a customized JUnit RunListener. The other way is using TestNG xml suites. In both cases it is necessary to add to the tests execution a Listener provided by tap4j.
Let's speak more about each possible solution.
So, imagine we have a simple JUnit test class and we want to make it generates TAP results.
Using a JUnit test executor class
Example 5.1. sample.MyJUnitTestClass.java
package sample; import junit.framework.Assert; import junit.framework.TestCase; public class MyJUnitTestClass extends TestCase { public void testEquals() { Assert.assertTrue( "O".equals( "0" ) ); } }
Here we have a sample test class called MyJUnitTestClass with 1 method testEquals supposed to return passed as result.
We need then to create the JUnit test executor class, where we must add the JUnit TAP reporter listener.
Example 5.2. sample.RunJUnitSuiteWithListener.java
package sample; import org.junit.runner.JUnitCore; import org.tap4j.ext.junit.JUnitTestTapReporter; public class RunJUnitSuiteWithListener { public static void main(String[] args) { // Create a JUnit suite TestSuite suite = new TestSuite(); // Add every test class you want to the suite suite.addTestSuite(MyJUnitTestClass.class); // Instantiate a JUniteCore object JUnitCore core = new JUnitCore(); // Add TAP Reporter Listener to the core object executor core.addListener(new JUnitTestTapReporter()); // Run the test suite core.run(suite); } }
So, when we execute the RunJUnitTestWithListener class, it will run the MyJUnitTestClass with the JUnitTestTapReporter listener. As a result we are going to have 3 tap files. 1 for the suite, 1 for the class 1 for the method.
Example 5.3. sample.MyJUnitTestClass-SUITE.tap
1..1 not ok 1 - sample.MyJUnitTestClass#testEquals --- message: JUnit 4.0 Test testEquals(sample.MyJUnitTestClass) severity: High source: sample.MyJUnitTestClass#testEquals datetime: '2011-05-20T11:04:11' file: sample.MyJUnitTestClass line: '10' name: testEquals error: 'null' backtrace: "junit.framework.AssertionFailedError: null\n\tat junit.framework.Assert.fail(Assert.java:47)\n\ \tat junit.framework.Assert.assertTrue(Assert.java:20)\n\tat junit.framework.Assert.assertTrue(Assert.java:27)\n\ \tat sample.MyJUnitTestClass.testEquals(MyJUnitTestClass.java:10)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native\ \ Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)\n\ \tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)\n\ \tat java.lang.reflect.Method.invoke(Method.java:597)\n\tat junit.framework.TestCase.runTest(TestCase.java:168)\n\ \tat junit.framework.TestCase.runBare(TestCase.java:134)\n\tat junit.framework.TestResult$1.protect(TestResult.java:110)\n\ \tat junit.framework.TestResult.runProtected(TestResult.java:128)\n\tat junit.framework.TestResult.run(TestResult.java:113)\n\ \tat junit.framework.TestCase.run(TestCase.java:124)\n\tat junit.framework.TestSuite.runTest(TestSuite.java:243)\n\ \tat junit.framework.TestSuite.run(TestSuite.java:238)\n\tat junit.framework.TestSuite.runTest(TestSuite.java:243)\n\ \tat junit.framework.TestSuite.run(TestSuite.java:238)\n\tat org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)\n\ \tat org.junit.runner.JUnitCore.run(JUnitCore.java:157)\n\tat org.junit.runner.JUnitCore.run(JUnitCore.java:145)\n\ \tat sample.RunJUnitSuiteWithListener.main(RunJUnitSuiteWithListener.java:56)\n" ...
Example 5.4. sample.MyJUnitTestClass.tap
1..1 not ok 1 - sample.MyJUnitTestClass#testEquals --- message: JUnit 4.0 Test testEquals(sample.MyJUnitTestClass) severity: High source: sample.MyJUnitTestClass#testEquals datetime: '2011-05-20T11:04:11' file: sample.MyJUnitTestClass line: '10' name: testEquals error: 'null' backtrace: "junit.framework.AssertionFailedError: null\n\tat junit.framework.Assert.fail(Assert.java:47)\n\ \tat junit.framework.Assert.assertTrue(Assert.java:20)\n\tat junit.framework.Assert.assertTrue(Assert.java:27)\n\ \tat sample.MyJUnitTestClass.testEquals(MyJUnitTestClass.java:10)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native\ \ Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)\n\ \tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)\n\ \tat java.lang.reflect.Method.invoke(Method.java:597)\n\tat junit.framework.TestCase.runTest(TestCase.java:168)\n\ \tat junit.framework.TestCase.runBare(TestCase.java:134)\n\tat junit.framework.TestResult$1.protect(TestResult.java:110)\n\ \tat junit.framework.TestResult.runProtected(TestResult.java:128)\n\tat junit.framework.TestResult.run(TestResult.java:113)\n\ \tat junit.framework.TestCase.run(TestCase.java:124)\n\tat junit.framework.TestSuite.runTest(TestSuite.java:243)\n\ \tat junit.framework.TestSuite.run(TestSuite.java:238)\n\tat junit.framework.TestSuite.runTest(TestSuite.java:243)\n\ \tat junit.framework.TestSuite.run(TestSuite.java:238)\n\tat org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)\n\ \tat org.junit.runner.JUnitCore.run(JUnitCore.java:157)\n\tat org.junit.runner.JUnitCore.run(JUnitCore.java:145)\n\ \tat sample.RunJUnitSuiteWithListener.main(RunJUnitSuiteWithListener.java:56)\n" ...
Example 5.5. sample.MyJUnitTestClass#testEquals.tap
1..1 not ok 1 - sample.MyJUnitTestClass#testEquals --- message: JUnit 4.0 Test testEquals(sample.MyJUnitTestClass) severity: High source: sample.MyJUnitTestClass#testEquals datetime: '2011-05-20T11:04:11' file: sample.MyJUnitTestClass line: '10' name: testEquals error: 'null' backtrace: "junit.framework.AssertionFailedError: null\n\tat junit.framework.Assert.fail(Assert.java:47)\n\ \tat junit.framework.Assert.assertTrue(Assert.java:20)\n\tat junit.framework.Assert.assertTrue(Assert.java:27)\n\ \tat sample.MyJUnitTestClass.testEquals(MyJUnitTestClass.java:10)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native\ \ Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)\n\ \tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)\n\ \tat java.lang.reflect.Method.invoke(Method.java:597)\n\tat junit.framework.TestCase.runTest(TestCase.java:168)\n\ \tat junit.framework.TestCase.runBare(TestCase.java:134)\n\tat junit.framework.TestResult$1.protect(TestResult.java:110)\n\ \tat junit.framework.TestResult.runProtected(TestResult.java:128)\n\tat junit.framework.TestResult.run(TestResult.java:113)\n\ \tat junit.framework.TestCase.run(TestCase.java:124)\n\tat junit.framework.TestSuite.runTest(TestSuite.java:243)\n\ \tat junit.framework.TestSuite.run(TestSuite.java:238)\n\tat junit.framework.TestSuite.runTest(TestSuite.java:243)\n\ \tat junit.framework.TestSuite.run(TestSuite.java:238)\n\tat org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)\n\ \tat org.junit.runner.JUnitCore.run(JUnitCore.java:157)\n\tat org.junit.runner.JUnitCore.run(JUnitCore.java:145)\n\ \tat sample.RunJUnitSuiteWithListener.main(RunJUnitSuiteWithListener.java:56)\n" ...
As we have only one test suite with one test class and only one test method, all 3 files have exactly the same content about tests.
Pay attention! When you run the executor class it is not going to show the results on JUnit eclipse view. It runs in background and generates the TAP files in the project root. You need to refresh your project on navigator view to see the tap files that were generated
Finally the command line for execution of the class is
Example 5.6.
java -classpath %CLASSPATH%;junit-4.0.jar;jcommander-1.5.jar;commons-io-1.4.jar; guice-2.0.jar;commons-lang-2.5.jar;bsh-2.0b4.jar;snakeyaml-1.7.jar; aopalliance-1.0.jar;tap4j-1.4.3.jar;. RunJUnitTestWithListenerClass
Using TestNG suite xml files to execute your JUnit tests
This is strange, but it is a very good idea. It is easy to implement and works perfectly as TestNG can interpret JUnit and run just like TestNG. Here, you only need to create xml suite files with the tap4j listeners, just like you would do if the tests were made with TestNG. The only difference is that you need to set the "junit" attribute inside "<suite<" branch to "true". Really easy no? TestNG takes care of the rest.
So your suite xml file will look like this:
Example 5.7. sample.MyJUnitTestClass#testEquals.tap
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="JUnit tests with TestNG suite" verbose="0" parallel="false" junit="true"> <listeners> <listener class-name="org.tap4j.ext.testng.SuiteTAPReporter" /> <listener class-name="org.tap4j.ext.testng.TestTAPReporter" /> </listeners> <test name="JUnit tests with TestNG suite" preserve-order="false"> <classes> <class name="sample.MyJUnitTestClass"/> </classes> </test> </suite>
The results are going to be given just like in the other way.