Seam Integration Tests with JUnit
exuisitus Sep 12, 2009 9:41 PMI am evaluating seam for a project. IDE is Eclipse, test framework JUnit.
The discussions about using JUnit in this forum gave some hints but not a
really a solution. So I had do dive into the Seam documentation an cook my
own soup, which I would like to share with the community.
The solution is generic, thus reusable and can be packed in a library.
It consists of two extendible classes which permit to use integration
tests à la TestNG out of the box.
Concept
A sub class of AbstractSeamTest to be in turn subclassed by a test suite (test class) implementation:
TestClass -> [JUnitSeamTest] -> AbstractSeamTest
A class to be subclassed for running multiple test suites (Suite.class runner).
MultipleTestClasses -> [JUnitSeamTestSuiteRunner]
Implementation
JUnitSeamTest.java
import org.jboss.seam.mock.AbstractSeamTest; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; /** * Superclass for JUnit Seam integration tests. * A Seam integration test can extend this class for use with JUnit. * * One or all of the JUnit life cycle methods can, but must not, be * overwritten by the extending class. If you do, you m u s t assign the correct * annotation and call super.xxxx() or the static equivalent * JUnitSeamTest.xxxx() in the overriding method. * * For batch processing, the Suite.class runner class sets the batch flag to true * in order to prevent multiple start and stops of the embedded container while * executing the individual test files. * * @author Rainer Schön * @date Sep 09 */ public class JUnitSeamTest extends AbstractSeamTest { // static helper instance to call non static methods in // a static method private static JUnitSeamTest seamTest = new JUnitSeamTest(); private static boolean batch = false; /* * JUnit test life cycle methods. */ @BeforeClass public static void setUpBeforeClass() throws Exception { if (!batch) seamTest.startContainer(); } @AfterClass public static void tearDownAfterClass() throws Exception { if (!batch) seamTest.stopContainer(); } @Before public void setUp() throws Exception { setupClass(); begin(); } @After public void tearDown() throws Exception { end(); cleanupClass(); } /* * Helper methods */ // starts the JBoss embedded ejb container public void startContainer() throws Exception { super.startSeam(); } // stops the JBoss embedded ejb container public void stopContainer() throws Exception { super.stopSeam(); } public boolean isBatch() { return batch; } // used by a JUnit.Suite runner to set the batch flag public void setBatch(boolean fBatch) { batch = fBatch; } }
JUnitSeamTestSuiteRunner.java
import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; /** * Superclass for running Seam integration tests in batch mode. This * class does n o t extend JUnitSeamTest but instead creates an instance * to start and stop the container at the beginning and the end of the * processing and to set the batch flag. * * The subclass must only assign the @SuiteClasses({x.class, y.class}) * annotation. * * @author Rainer Schön * @Date Sep 09 */ @RunWith(Suite.class) // JUnit batch runner public class JUnitSeamTestSuiteRunner { private static JUnitSeamTest seamTest = new JUnitSeamTest(); @BeforeClass public static void setUpBeforeClass() throws Exception { // set the flag to signal batch mode seamTest.setBatch(true); seamTest.startContainer(); } @AfterClass public static void tearDownAfterClass() throws Exception { seamTest.stopContainer(); seamTest.setBatch(false); } }
Examples
Run single test suite (test class)
import static org.junit.Assert.*; import java.util.List; import javax.faces.application.FacesMessage; import org.jboss.seam.faces.FacesMessages; import org.junit.Test; /** * Working example of a Seam integration test using the JUnit Seam integration * test port. * */ public class SeamIntegrationTestWithJUnit extends JUnitSeamTest { @Test public void testSomething() throws Exception { new FacesRequest("/some.xhtml") { @Override protected void updateModelValues() { // do some model updates here // test the results assertTrue(true); } @Override protected void invokeApplication() { // Invoke a method and test the outcome final String outcome = "fantastic"; assertTrue(outcome != null && outcome.equals("fantastic")); } @Override protected void renderResponse() throws Exception { final String msg = "This JUnit Seam Test port is great!"; // test some results in the render response phase List<FacesMessage> messages = FacesMessages.instance().getCurrentGlobalMessages(); messages.add(new FacesMessage(msg)); assertTrue(messages.size() == 1); assertEquals(FacesMessage.SEVERITY_INFO, messages.get(0).getSeverity()); assertTrue(messages.get(0).getSummary(). contains(msg)); } }.run(); } }
Run multiple test suites (test classes)
import org.junit.runners.Suite.SuiteClasses; /** * Example for running multiple Seam integration test classes at once. */ @SuiteClasses({ OneTest.class, TwoTest.class, ThreeTest.class, NTest.class}) public class MultipleSeamIntegrationTests extends JUnitSeamTestSuiteRunner{ // empty class, only used to assign @SuiteClasses annotation with // the array of test classes to run }
Important
Ensure, that the embedded JBoss container fires up correctly.
If you use Java 6, you must start the VM with the follwing argument:
-Dsun.lang.ClassLoader.allowArraySyntax=true
in Eclipse put this argument in the JUnit launch configuration (box VM) for each
test you want to run (which you will forget most of the time for the first launch!).