Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Learn Scala with Specs2 Spring

Use Scala code to safely test and debug Spring-based Java apps

  • Print
  • Feedback

Page 4 of 5

Integration testing in Specs2 Spring

An integration specification tests several application components working together. Integration testing is complicated by the fact that Java EE application components often have external dependencies such as javax.sql.DataSource, javax.mail.Session, javax.jms.Queue, javax.jms.Topic, javax.transaction.TransactionManager, and many others.

In order to keep application source code as maintainable as possible, and to remove as much complexity from the build process as possible, we want to keep the source code that is running on the development machines in sync with the source code that is deployed on the pre-production and production servers.

Each machine will of course have its own RDBMS and JMS configuration, and some details of the configuration likely are (and should be) inaccessible to us as developers. For instance, the RDBMS configuration for the production machine should not be left to developers.

If we were testing the Spring way, we'd use the spring-test artifact with the @ContextConfiguration annotation on a JUnit test. Spring would then construct the components under test by examining the Spring configuration files. The spring-test would leave us to set up the JNDI environment, a non-trivial and repetitive task. So we have two challenges: first, to bring the equivalent of spring-test to Scala and Specs2, then to set up the JNDI environment for the test.

Setting up the JNDI environment

Java allows us to register resources in JNDI; these resources could include a JDBC DataSource, a JMS ConnectionFactory, a Queue, a JavaMail Session, and so on. While it's a simplification, you could think of JNDI as a Map<String, Object> (or, speaking in Scala: Map[String, AnyRef]). Essentially, the application consumes objects from JNDI and uses them in its code. In Spring applications, the consumed JNDI resources will most likely become beans in the Spring ApplicationContext.

Learn more

For further details of the JNDI and Spring setup code, see the Specs2 Spring documentation from Cake Solutions.

In addition to test code we need to include code that sets up JNDI for the test. The JDNI code should be reusable, and it also must run prior to other code in the test case. We see this in Listing 4, where the specification's setup code prepares the JNDI environment, then adds the Spring ApplicationContext, and finally injects the required beans into the specification, as shown in Listing 4.

As developers, we code the @DataSource, @TransactionManager, and @ContextConfiguration annotations. Specs2 Spring then sets up the JNDI environment for the test and builds the Spring ApplicationContext with the components under test. Finally, it injects the instances of the components from the ApplicationContext into the test. (Note @Autowired var riderManager: RiderManager = _ in Listing 4.)

Listing 4. Specs2 Spring

@DataSource(name = "java:comp/env/jdbc/test",
        driverClass = classOf[JDBCDriver], url = "jdbc:hsqldb:mem:test")
    @TransactionManager(name = "java:comp/TransactionManager")
    @ContextConfiguration(Array("classpath*:/META-INF/spring/module-context.xml"))
    class RiderManagerSpec extends Specification {
        @Autowired var riderManager: RiderManager = _

        "Generate 10 riders" in {
            val count = 10
            this.riderManager.generate(count)
            this.riderManager.findAll.size() must be_==(count)
        }

    }


The Specs2 Spring code in Listing 4 handled much of our test setup with very little code. The the body of the specification ("Generate 10 riders") also leveraged some helpful features of Specs2. Specs2 Spring prepared the JNDI environment for the test and instantiated the Spring ApplicationContext, then it injected the RiderManager instance into the RiderManagerSpec.

Listing 5 shows the testing portion of code from Listing 4. Note that the Specs2 code, written in Scala, is shorter and clearer than Java code, while still expressing the same test.

Listing 5. The testing code

...
    class RiderManagerSpec extends Specification {
        ...
    
        "Generate 10 riders" in {
            val count = 10
            this.riderManager.generate(count)
            this.riderManager.findAll.size() must be_==(count)
        }

    }

The "Generate 10 riders" specification's body clearly expresses what is being tested with as little syntactic noise as possible. Instead of Java's cumbersome Assert.assertThat(this.riderManager.findAll.size(), CoreMatchers.is(count)), Scala gave us: this.riderManager.findAll.size() must be_==(count). (Using static imports in Java would be another way to get at more elegant syntax, but I feel that it is still far too verbose; e.g., assertThat(this.riderManager.findAll.size(), is(count)).)

Running parallel examples in Specs2

In some cases you will want to run more than one test (or example in Specs2) in a specification. It should be possible to run the examples in parallel, in multiple threads. So, suppose that we have two examples in our RiderManagerSpec, and that both of them would modify the database. If we run both examples in parallel, it will be difficult to ensure that they do not influence each other. We don't want to lose the parallel nature of Specs2, but we do want to isolate every test example. This is a problem for transactional semantics!

It is easy to modify the specification to run every example in its transaction and then roll back that transaction when the example finishes, as shown in Listing 6.

Listing 6. Transactional example semantics

@Transactional
    @DataSource(name = "java:comp/env/jdbc/test",
        driverClass = classOf[JDBCDriver], url = "jdbc:hsqldb:mem:test")
    @TransactionManager(name = "java:comp/TransactionManager")
    @ContextConfiguration(Array("classpath*:/META-INF/spring/module-context.xml"))
    class RiderManagerSpec extends Specification {
        ...
    }

Notice the @Transactional annotation on the specification. When Specs2 Spring sees this annotation, it will look for a PlatformTransactionManager bean in the Spring context constructed for the test. It will then use that PlatformTransactionManager to wrap the example in a transaction. It will automatically roll back the completed transaction, regardless of whether it completed successfully or failed.

Now let's take a quick look at what Specs2 Spring does to simplify writing acceptance specifications.

Acceptance specifications in Specs2 Spring Web

Version 1.0 of Specs2 Spring will support acceptance testing of servlet-based applications. This will include web applications that interact with browsers or other systems and use DispatcherServlet or the MessageDispatcherServlet. Specs2 Spring Web will enable developers to write specifications that can verify the behavior of the entire system, including its interface. At the same time, it will let specifications access the underlying structure of the application. Listing 7 shows an acceptance specification in Specs2 Spring.

  • Print
  • Feedback

Resources
  • Specs2 Spring is a Specs2 extension for BDD & testing typical Spring enterprise applications in Scala.
  • The Spring framework is a de-facto standard for implementing loosely-coupled, flexible, and testable Java EE applications.
  • Specs2 is a Scala BDD testing framework.
  • Scala is a strongly-typed object-functional scalable language.
  • "Dependency injection vs. Cake pattern" (Cake Solutions Team Blog, December 15, 2011): Learn more about the cake pattern as an alternative to dependency injection, as it is implemented in several web application frameworks.

More from JavaWorld