Tuesday, June 4, 2013

Green's Opinion at Tasktop

Green’s Opinion has really taken a back seat since I joined Tasktop three years ago as VP of Engineering. Writing just didn’t make the top of the pile when dealing with all of the responsibilities of the role. Well, it’s time I dusted off the old writing hat! As of May 9th I’ve taken on a new role at Tasktop, VP of Architecture. Green’s Opinion has found a new home, and to kick it off I’ve written an article Testing for the API Economy. Enjoy!

Thursday, July 29, 2010

Testing REST Web Services with JPA and Spring

REST Web Services can be particularly difficult to test, with the need for networking, a web container, multiple threads and transaction management creating extra complexity beyond your standard unit test. In this article I demonstrate patterns designed to address this complexity while enabling complete testing of your REST web service stack.

The ideal web service unit test will use the same principles discussed in my previous article:

  1. clean database with mocked data so that we can reliably test specific scenarios
  2. rollback to avoid side-effects after our test
  3. in-memory database so that no environment setup is required

In addition, we’ll need to run a web container for our unit test. To maintain a zero-setup test environment, we’ll have our unit test start a web container for the purpose of running our web service. By having each test start and stop the web container, tests become very simple to run and we’re guaranteed that our tests will have a clean environment with no external dependencies.

Web Container

Normally starting a web container is difficult to do in a unit test, and container startup time can be a problem — however with the right choice of web container we can overcome these problems. Winstone is a small, fast web container that is designed to be embedded in Java programs. By using Winstone, we’ll be able to start and stop the web container as part of our unit test setup and tear-down with relative ease.

Starting Winstone is as simple as this:

 Map args = new HashMap();
args.put("webroot", pathToWebRoot);
args.put("httpPort", String.valueOf(port));
Launcher.initLogger(args);

// start winstone
winstoneLauncher = new Launcher(args);

Winstone only takes a couple of seconds to start up. Shutting it down is as simple as this:

 if (winstoneLauncher.isRunning()) {
winstoneLauncher.shutdown();
}

To hide the details of winstone from our unit tests, we can create a class WebApplicationContainer, which is responsible for starting choosing a port, starting/stopping Winstone, and providing a base URL for our tests:

public class WebApplicationContainer {

private static final Random random = new Random(System.currentTimeMillis());

private Launcher winstoneLauncher;

private File webRoot;

private int port;

/**
* start the webserver, guarantees that the webserver is started upon return.
* @see #stop()
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void start() {
if (winstoneLauncher != null) {
throw new IllegalStateException("already started");
}
port = findAvailablePort();


Logger log = Logger.getLogger(WebApplicationContainer.class.getName());
log.fine("Starting web container on "+getBaseUrl());

Map args = new HashMap();
try {
args.put("ajp13Port", "-1");
args.put("useJasper", "false");
args.put("webroot", webRoot.getAbsolutePath());
args.put("httpPort", String.valueOf(port));
Launcher.initLogger(args);

// start winstone
winstoneLauncher = new Launcher(args);

// wait for Winstone to finish starting up
// we do that by attempting to connect via socket
final int maxRetries = 150;
for (int x = 0; x < maxRetries; ++x) {
if (testForSuccessfulStartup()) {
break;
}
if (x == maxRetries - 1) {
throw new IllegalStateException(
String.format("Connection to localhost:%s failed."+
" Did the web container start up successfully?"));
}
// wait and then try again
Thread.sleep(100L);
}
Logger.getLogger(WebApplicationContainer.class.getName()).
info("Started web container at "+getBaseUrl());
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private int findAvailablePort() {
...
}

private boolean testForSuccessfulStartup() {
// test to see if the web container is listening on the address/port combo
try {
Socket socket = SocketFactory.getDefault().createSocket("localhost", port);
socket.close();
return true;
} catch (UnknownHostException e) {
throw new IllegalStateException(e);
} catch (IOException e) {
return false;
}
}

/**
* stop the web container
* @see #start()
*/
public void stop() {
if (winstoneLauncher == null) {
throw new IllegalStateException();
}

winstoneLauncher.shutdown();
winstoneLauncher = null;
}

public String getBaseUrl() {
return String.format("http://localhost:%s/", port);
}
...
}

REST Service Unit Test

A complete test for our web service ends up looking like this:

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
public class BlogServiceClientTest extends BlogServiceTest {
@Autowired
private BlogServiceClient blogServiceClient;

@Autowired
private WebApplicationContainer webContainer;

@Before
public void before() {
webContainer.setWebRoot(computeWebRoot());
webContainer.start();

blogServiceClient.setBaseUrl(webContainer.getBaseUrl()+"api");
// use the client instead of the service directly
service = blogServiceClient;
}

@After
public void after() {
if (webContainer.isStarted()) {
webContainer.stop();
}
}
}

You might be thinking "where are the @Test methods?". The beauty of our web service test is that it extends our service test: all of the test methods we were running before using direct method calls are now also run over our web service protocol. By using inheritance, other than setup of our web service there’s nothing else to do. In other words, our service tests are run twice: once using Java method calls, and again over-the-wire using our web service. This ensures that we see consistent behaviour in both modes of execution.

BlogServiceClient is an implementation of BlogService (our service interface under test) based on Spring’s RestTemplate. It’s a REST client for our service, implementing the same Java interface as our server-side service. This enables us to substitute the REST client service implementation in our test.

Transaction Management and JPA

Now that we’re able to start our web service and run tests we’re done, right? Not quite: we still need to manage transactions and our test data. This is somewhat more complicated with our web service: recall that we want our unit test to have the following qualities:

  • clean database on startup
  • run in a transaction that rolls back after the test
  • mocks all of its own data

Employing the techniques we’ve already established in Patterns for Better Unit Testing with JPA helps, but is not quite enough.

Our service implementation is running in a web container. The web container services incoming HTTP requests with threads in a thread pool. Our service is pretty much guaranteed to be running on a distinct thread, not the same thread as that running our unit test method. As a result our service bean will be running in it’s own transaction context. There are two problems that arise from this:

  • our service won’t be able to see the data we’ve mocked up in our test
  • our service method will commit its transaction

Both of these things are undesirable. To overcome this problem we’ll apply a little trickery: we’ll provide an entity manager that is shared by both the test thread and the web container thread servicing our HTTP requests, and we’ll prevent any commit or rollback from occurring on that entity manager while it’s in use in a unit test. We do this by wrapping the entity manager factory in our test environment:

<bean class="greensopinion.restexample.test.jpa.TestEntityManagerFactory" 
id="blogDomain">
<property name="delegate">
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceXmlLocation"
value="classpath*:/persistence-test.xml"/>
</bean>
</property>
</bean>

Our TestEntityManagerFactory employs the standard delegate pattern, with the exception that it changes the default behaviour of createEntityManager():

 public EntityManager createEntityManager() {
if (theEntityManager == null) {
theEntityManager = delegate.createEntityManager();
}
return new TestEntityManager(theEntityManager);
}

It creates and returns a singleton entity manager instance. This allows us to share a single entity manager between our unit test and the web container. We also wrap the entity manager so that we can control it’s lifecycle (we prevent close()) and that of it’s transaction (we prevent commit() and rollback()).

While we know that the EntityManager is not thread safe, it’s okay to share it between threads providing that no two threads access it at the same time. Since our REST client will block on any calls to the server, we’re not at risk of concurrent access.

Source Code

Complete, working source code demonstrating these patterns and others is available on GitHub:

http://github.com/dgreen99/greensopinion.restexample

The source contains two Eclipse projects: one for the web application, and one for unit tests. The unit tests all run and pass, and the web application can be started and deployed with a MySQL database.

Service Patterns

The service is split into the following:

  • Service interface – defines the service contract
  • Service bean – implements the service over JPA
  • Service controller – exposes the service using Spring REST
  • Service client – implements client end of the REST service, used in our tests

This gives us a good separation of concerns, and client code need not always know if it’s calling an in-process or out-of-process service.

JPA domain objects are exposed by the service interface. This helps in a few ways:

  • The service is usable in other parts of the application that deal with the domain
  • It helps to reduce the amount of code that must be written

However it has drawbacks:

  • It exposes the design of our domain, limiting our ability to change it in the future
  • Changes to the domain may inadvertently break the service interface for third-party clients
  • The service controller must be careful to expose shallow copies of our domain objects

This approach may be feasible for some projects. It’s common to see transfer objects as well, which allows a service to be explicit about it’s data model without exposing the domain implementation details.

Missing Functionality

Notably this sample code is missing two crucial aspects of a normal web application:

  1. Exception handling should be built-in to our service controller so that errors can be propagated gracefully.
  2. Data validation is not performed by the service bean.

These aspects of the sample application are left unimplemented.

Summary

Testing REST web services can be easy by following the following patterns:

  • implement a web service client to exercise your service from unit tests
  • run the web service in your tests with a lightweight embedded web container
  • share the entity manager and transaction context between the service and test

By applying these straight-forward techniques it’s possible to overcome the complexity inherent in testing a web service, enabling better coverage and higher quality applications.

References

Technologies used in this project:

Thursday, July 15, 2010

Patterns for Better Unit Testing with JPA

Over the years I’ve run across many projects, which tend to fall into one of two categories: those projects that have great confidence, energy and momentum, running hundreds (or thousands) of unit tests dozens of times every day; and those projects where the effort of writing and running unit tests is high enough that tests aren’t maintained and as a result no one on the team really knows if their software works. So how do we get our project into the first category? Below I highlight a few patterns and practices that significantly lower the bar to creating a solid test suite, enabling your team to adopt a practice and culture of complete test coverage.

Setup and Speed

Configuration, setup and maintenance of environments creates a significant barrier to a well-exercised and maintained test suite. Ideally we want to enable running tests with zero setup. Data-intensive applications need a database, which are notoriously hard to configure and setup. We’ll use a database for our tests, but instead of connecting to an external one the database will start up and run as part of the unit test. This gives us the following:

  • zero setup: no installation, no shared machine, no maintenance, no JDBC urls, no passwords
  • in-memory and fast
  • can run anywhere, even when not on a network
  • clean, with no rogue data that could affect our tests
  • no deadlocks

My first reaction when I saw this approach in use was “how can tests be meaningful if they're not run on the same database software that is used in production”? The answer is two-sided. We should be running these tests on the same database software. In fact, I encourage you to do that — on your continuous integration build server. The tests are meaningful in that they can make assertions and exercise your code. Database platform-specific issues can be flushed out on the build server, which can run these same tests using a different configuration.

To set this up I recommend using Apache Derby or Hypersonic. Here’s how it’s done with Hypersonic and Eclipselink as our JPA provider:

  1. add hsqldb.jar to the test project classpath (this is for Hypersonic)
  2. configure your JDBC connection to use an in-memory database URL as follows: jdbc:hsqldb:mem:tests
  3. configure your persistence.xml with the right SQL dialect. For Eclipselink this is done by setting eclipselink.target-database to HSQL as follows:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="blogDomain" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
... snip ...
<properties>
<property name="eclipselink.target-database" value="HSQL"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode"
value="database"/>
<property name="eclipselink.weaving" value="false"/>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
</persistence>

With this configuration the test suite will create a new in-memory database every time it’s run, and Eclipselink will create the necessary tables to persist our data. We’ve managed to eliminate the need for any kind of setup or external database to run our tests. That’s great, but now we’ve got an empty database, where does our data come from?

Test Data

Data-intensive applications need data for their tests — that’s a given. For our tests to run reliably and check specific scenarios every time, we need the data used by each test case to be the same every time tests are run. The best way to do this is to have our tests mock up the data. Mocking data can be cumbersome, however that can be alleviated by using mock factories for our domain objects. Mock factories populate domain objects with values such that they’re ready to use as-is. Where needed, tests can alter the state of domain objects to create the desired scenario. Here’s an example:

 @Test
public void testUpdateBlog() {
Blog blog = MockFactory.on(Blog.class).create(entityManager);
entityManager.flush();
entityManager.clear();

blog.setName(blog.getName()+"2");

Blog updatedBlog = service.updateBlog(blog);
assertNotNull(updatedBlog);
assertNotSame(updatedBlog,blog);
assertEquals(blog.getName(),updatedBlog.getName());
assertEquals(blog.getId(),updatedBlog.getId());
}

In this example the test verifies that the Blog entity is properly updated by the service. Notice that the test didn’t have to populate the blog object before persisting it: all of the required values were filled in by the MockFactory.

For this to work, we’ll need a MockFactory implementation. This is what ours looks like:

/**
* A factory for domain objects that mocks their data.
* Example usage:
* <pre><code>
* Blog blog = MockFactory.on(Blog.class).create(entityManager);
* </code></pre>
* @author David Green
*/
public abstract class MockFactory<T> {

private static Map<Class<?>,MockFactory<?>> factories =
new HashMap<Class<?>, MockFactory<?>>();
static {
register(new MockBlogFactory());
register(new MockArticleFactory());
}
private static void register(MockFactory<?> mockFactory) {
factories.put(mockFactory.domainClass,mockFactory);
}
@SuppressWarnings("unchecked")
public static <T> MockFactory<T> on(Class<T> domainClass) {
MockFactory<?> factory = factories.get(domainClass);
if (factory == null) {
throw new IllegalStateException(
"Did you forget to register a mock factory for "+
domainClass.getClass().getName()+"?");
}
return (MockFactory<T>) factory;
}

private final Class<T> domainClass;

private int seed;

protected MockFactory(Class<T> domainClass) {
if (domainClass.getAnnotation(Entity.class) == null) {
throw new IllegalArgumentException();
}
this.domainClass = domainClass;
}

/**
* Create several objects
* @param entityManager the entity manager, or null if the mocked objects
* should not be persisted
* @param count the number of objects to create
* @return the created objects
*/
public List<T> create(EntityManager entityManager,int count) {
List<T> mocks = new ArrayList<T>(count);
for (int x = 0;x<count;++x) {
T t = create(entityManager);
mocks.add(t);
}
return mocks;
}

/**
* Create a single object
* @param entityManager the entity manager, or null if the mocked object
* should not be persisted
* @return the mocked object
*/
public T create(EntityManager entityManager) {
T mock;
try {
mock = domainClass.newInstance();
} catch (Exception e) {
// must have a default constructor
throw new IllegalStateException();
}
populate(++seed,mock);
if (entityManager != null) {
entityManager.persist(mock);
}
return mock;
}

/**
* Populate the given domain object with data
* @param seed a seed that may be used to create data
* @param mock the domain object to populate
*/
protected abstract void populate(int seed, T mock);


private static class MockBlogFactory extends MockFactory<Blog> {
public MockBlogFactory() {
super(Blog.class);
}

@Override
protected void populate(int seed, Blog mock) {
mock.setName("Blog "+seed);
}
}

private static class MockArticleFactory extends MockFactory<Article> {

public MockArticleFactory() {
super(Article.class);
}

@Override
protected void populate(int seed, Article mock) {
mock.setAuthor("First Last");
mock.setTitle("Article "+seed);
mock.setContent("article "+seed+" content");
}
}
}

This implementation uses static methods and a static initializer. It’s not very Spring-like. If you prefer you could get rid of all the statics and instead have Spring inject (autowire) your mock factories into your test classes.

In our implementation we use an integer seed to help us produce values that vary. This implementation is fairly trivial, however if needed we could apply more advanced techniques such as using data dictionaries to source data. Such mock factories should populate enough values that the mocked domain object can be persisted: all not-null properties should have values. To ensure that this is true over the lifespan of our project, it’s important to have a test:

/**
* test that {@link MockFactory mock factories} are working as expected
*
* @author David Green
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( { "/applicationContext-test.xml" })
@Transactional
public class MockFactoryTest {

@PersistenceContext
private EntityManager entityManager;

@Test
public void testCreateBlog() {
Blog blog = MockFactory.on(Blog.class).create(entityManager);
assertNotNull(blog);
assertNotNull(blog.getName());
entityAssertions(blog);
entityManager.flush();
}
@Test
public void testCreateArticle() {
Blog blog = MockFactory.on(Blog.class).create(entityManager);
Article article = MockFactory.on(Article.class).create(null);
article.setBlog(blog);
entityManager.persist(article);
assertNotNull(article);
assertNotNull(article.getTitle());
assertNotNull(article.getContent());
entityAssertions(article);
entityManager.flush();
}
private void entityAssertions(AbstractEntity entity) {
assertNotNull(entity.getId());
assertNotNull(entity.getCreated());
assertNotNull(entity.getModified());
}
}

The key behind this approach is that each test mocks its own data. Where data models are signifcantly more complex, utility functions can use these mock factories to create common scenarios.

Now that we’ve got an easy way to produce data in our tests, how do we eliminate potential for side-effects between tests? That part is easy: we ensure that transactions are rolled back after every test. In our example we’re using Spring to run our tests via SpringJUnit4ClassRunner. Its default behaviour is to roll back after each test is run, however if you’re not using Spring you should have something like this in an abstract test case class:

 /**
* Overriding methods should call super.
*/
@After
public void after() {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
}

Summary

We’ve seen how we can make unit testing easy with a few simple patterns:

  • in-memory database
  • mocked data
  • roll back transactions after each test

By employing these simple techniques, tests are easy to write and run. Your team will get addicted to thorough test coverage as the number of tests being run increases and provides tangible feedback of their progress.

In my next article I’ll post complete working source code and show how these techniques can be taken a step further in testing Spring REST web services.