Integration Testing in Seam

Posted on Friday, February 26, 2010

0


Once you are done with the unit testing for the individual layers in Seam, you would like to check the complete vertical slice. There are a couple of ways to do integration testing

  • Integration Testing the application through the code using JUnit.
  • Integration Testing the application through the UI using frameworks like Fitnesse and Selenium.

In this post, we would talk about integration testing using JUnit.

By default Seam integrates out of the box with TestNG. In order to make Seam work with JUnit, you have to extend the AbstractSeamTest.

You’ll need to provide an implementation of AbstractSeamTest which does the following:


/**
 * 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.
 *
 */
public class JUnitSeamTestHelper extends AbstractSeamTest {
 // static helper instance to call non static methods in
 // a static method
 private static JUnitSeamTestHelper seamTest = new JUnitSeamTestHelper();
 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;
 }
}

Now your integration tests much extend the JUnitSeamTestHelper.


public class SearchIntegrationTest extends JUnitSeamTestHelper {

 @Test
 public void testHitSearchPage() throws Exception {
 new NonFacesRequest("/search.xhtml") {

 protected void renderResponse() throws Exception {
 List<FacesMessage> messages = FacesMessages.instance().getCurrentMessages();
 Assert.assertEquals(0, messages.size());
 }
 }.run();

 }

As you would notice that you can trigger a NonFacesRequest as well as a FacesRequest. Once you send in a FacesRequest, and add the values to form etc that you need to submit in the updateModelValues() method, then you can invoke the relevant action as if the user is clicking the button/link etc. Here your complete integration flow gets triggered which uses the pages.xml to decide the navigation.

Refer to the following test


@Test
 public void testSearch() throws Exception {

 login();

 new FacesRequest("/search.xhtml") {

 // Emulate that the user is filling up the form
 protected void updateModelValues() throws Exception {
 setValue("#{companySearchCriteria.companyName}", "google");
 setValue("#{companySearchCriteria.city}", "mountain view");
 setValue("#{companySearchCriteria.state}", "CA");
 }

 // Emulates user clicking the form
 protected void invokeApplication() throws Exception {
 invokeMethod("#{searchAction.findCompanies(companySearchCriteria)}");
 }

 protected void renderResponse() throws Exception {
 // check the message
 List<FacesMessage> messages = FacesMessages.instance().getCurrentMessages();
 Assert.assertEquals(0, messages.size());

 List<Company> companyList = (List<Company>)getValue("#{searchAction.companies}");
 Assert.assertEquals(2, companyList.size());
 }
 }.run();

 }

You can assert for any FacesMessages that you have put and you expect to be reflected on the pages. You can also assert the outjection of objects that you would expect to be outjected. For example consider the following code segment


protected void renderResponse() throws Exception {
 // check the message
 List<FacesMessage> messages = FacesMessages.instance()
 .getCurrentMessages();
 Assert.assertEquals(1, messages.size());
 Assert.assertEquals("Welcome, admin", messages.get(0)
 .getSummary());

 // Check the user which is outjected after login
 User user = (User) getValue("#{loggedInUser}");
 Assert.assertEquals("admin", user.getUsername());
 }

Here as you would observe that apart from asserting on the message that we expect, we also assert that the loggedInUser is getting outjected. Likewise you could test for other specific scenarios like checking the object in a particular context and so on.

Advertisements
Posted in: Java