Help

Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

Test Your Module

When developing any system or software, it's important to test as much of that system as possible. Web frameworks are no exception; comprehensive, well-designed unit tests are critical for long-term success and maintenance. We want to be able to confidently stand behind the stability of Seam 3. So please, test your module.

Guidelines:
  • All use-cases should be accompanied by a test.
  • Tests are code, make sure they are clear and make sense. If they do not, chances are that the architecture needs to be re-thought.
  • A module should not have a final release until it is well-tested.
Test structure:

Maven follows strict testing practices by executing the tests on every build. All unit tests should be placed in the /src/test/java folder, under the corresponding package to the class under test.

module/
   |- src/
   |   |- main/
   |   |   |- java/
   |   |   |   |- org/
   |   |   |   |  |- jboss/
   |   |   |   |  |  |- (ClassUnderTest).java
   |   |- test/
   |   |   |- java/
   |   |   |   |- org/
   |   |   |   |  |- jboss/
   |   |   |   |  |  |- test/
   |   |   |   |  |  |  |- (ClassUnderTest)Test.java
Set up the test suite:

Add the following dependencies to pom.xml:

   <properties>
      <arquillian.version>1.0.0.Alpha1</arquillian.version>
      <junit.version>4.8.1</junit.version>
   </properties>

   <dependencies>
      <!-- Test Dependencies -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>${junit.version}</version>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.jboss.arquillian</groupId>
         <artifactId>arquillian-junit</artifactId>
         <version>${arquillian.version}</version>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.jboss.arquillian.container</groupId>
         <artifactId>arquillian-weld-embedded</artifactId>
         <version>${arquillian.version}</version>
         <scope>test</scope>
      </dependency>
   </dependencies>

JUnit

JUnit is the Java industry-standard unit-testing framework. It has the best IDE support and it integrates cleanly with Arquillian. Therefore, we recommend that you choose it over TestNG.

The one feature that TestNG has over JUnit 4 is groups. The categories feature introduced in JUnit 4.8.1 promises to fill this void, but work still needs to allow this feature to work with Arquillian. Stay tuned for details.

Write a JUnit test

Tests are run automatically during a Maven build, such as mvn test, mvn package, or mvn install. It's important to note, that tests are only run if the name of the test class ends in 'Test' -- e.g: SimpleMathTest.java

Note the simplicity of the unit test. Each test-case should have only one class under test. E.g: The SimpleMathTest should only test behavior of 'MathImpl.java'... Mixing testable classes in a test-case can lead to missed scenarios, bugs.

Math.java

public interface Math
{
   public int add(int a, int b);
   public int subtract(int a, int b);
}

MathImpl.java

public class MathImpl implements Math
{
   public int add(int a, int b)
   {
      return a + b;
   }
   public int subtract(int a, int b)
   {
      return a - b;
   }
}

The unit test case:

public class MathImplTest
{
   public void testAdd() throws Exception
   {
      Math m = new MathImpl();
      assertEquals(5, m.add(2, 3));
   }

   public void testSubtract() throws Exception
   {
      Math m = new MathImpl();
      assertEquals(-1, m.subtract(2, 3));
   }
}

Arquillian

Arquillian is the next-generation in-container integration testing framework. Allowing fully dependency-injected unit testing, even EJB and Web Services. Arquillian can be used to test nearly every Java EE component, but for the purpose of this document, we'll just show you the most common case - how to test managed beans.

Write an Arquillian Unit/Integration Test

Arquillian is where unit testing starts to get a little more exciting. This is where we actually test managed beans provided through dependency injection. While still using JUnit as the core testing framework, Arquillian tests a wider scope of the system, typically, than a pure JUnit test would; these are sometimes referred to as integration unit tests, or integration tests.

Your first Arquillian JUnit test-case:

Here we see the same unit test from above, but this time, using Arquillian to provide injection into the test case. This allows us to test components with many levels of dependency injection, or any other feature in CDI/Weld.

@RunWith(Arquillian.class)
public class ExternalContextProducerTest
{
   /**
    * Since Arquillian actually creates JAR files under the covers with ShrinkWrap,
    * the @Deployment is your way of controlling what is included in that Archive.
    * Note, each class utilized in your test case - whether directly or indirectly -
    * must be added to the deployment archive.
    */
   @Deployment
   public static Archive<?> createTestArchive()
   {
      return Archives.create("test.jar", JavaArchive.class).addClass(Math.class).addClass(MathImpl.class)
         .addManifestResource(new ByteArrayAsset(new byte[0]), ArchivePaths.create("beans.xml"));
   }

   // Arquillian enables @Inject directly in the test case class itself!
   @Inject Math m;

   
   public void testAdd() throws Exception
   {
      assertEquals(5, m.add(2, 3));
   }

   public void testSubtract() throws Exception
   {
      assertEquals(-1, m.subtract(2, 3));
   }

}

Now that's simplicity! However, you might say, Math is so simple, why did we bother to use Arquillian to test it?

When to use Arquillian

The answer is simple: In the above example, you probably wouldn't have needed to use Arquillian, you could have just stuck with JUnit, but as soon as you have a situation like the one below, you might decide that it's time for Arquillian; for example, if you wanted to test a decorator.

Decorators extend the functionality of an existing interface.

public class MathDecorator implements Math
{
   @Inject Math delegate;
   @Inject User user;
   @Inject Logger log;

   public int add(int a, int b)
   {
      log.trace("Add was invoked by: " + user);
      return delegate.add(a, b);
   }

   public int subtract(int a, int b)
   {
      log.trace("Subtract was invoked by: " + user);
      return delegate.subtract(a, b);
   }
}

Now in order to test the functionality here using only JUnit, you would need to create, instantiate, and set mocks for User and Logger, instantiate the decorator, then execute the test code. That's a lot of work that you don't really need to worry about if using Arquillian.

For instance, this is what the Arquillian test case would look like:

@RunWith(Arquillian.class)
public class MathDecoratorTest
{
   
   /**
    * Note in this example, we must add content to "beans.xml" in order to enable 
    * our decorator in CDI/Weld -- this is done in the deployment using the syntax below:
    */
   @Deployment
   public static Archive<?> createTestArchive()
   {
      return Archives.create("test.jar", JavaArchive.class).addClasses(Math.class, MathImpl.class, MathDecorator.class, MockUser.class, MockLogger.class)
         .addManifestResource(new ByteArrayAsset("<decorators><class>com.test.MathDecorator</class></decorators>".getBytes()), ArchivePaths.create("beans.xml"));
   }

   // Arquillian enables @Inject directly in the test case class itself!
   @Inject Math m;
   @Inject MockLogger log;
   @Inject User u;
   
   public void testAdd() throws Exception
   {
      m.add(2, 3);
      assertTrue(log.logged("Add was invoked by: " + u);
   }

   public void testSubtract() throws Exception
   {
      m.subtract(2, 3);
      assertTrue(log.logged("Subtract was invoked by: " + u);
   }

}

Pretty simple! No more creating chains of mocks -- just make sure all the right classes are included in the deployment, and you're good to go. Test just as you would write code in the system itself. Arquillian will start up CDI and perform all the Dependency injection and container functions for you!

Continuous integration

As soon as you have your tests ready, you'll want them to be run on a regular basis. If something breaks, you'll discover it soon, and you can easily isolate the commit that caused your tests to fail.

Setup a Hudson job for your module

There's an instance of the Hudson continuous integration server that will run your tests and publish the results. If something fails it will send you a notification email. To learn more, see Build Jobs

To set up a new Hudson job (or tweak an existing one) contact Seam QE team.