Using functors to handle test connections

A few days ago I was working on some functional tests that have the following structure:

      public void testSomething() throws Exception {
        // 1. istantiate the system
        // 2. interact with it through the UI
        connectDB();
        // 3. assert the state of the system by examining the DB
        relinquishDB();       

        // 4. interact a bit more through the UI
        connectDB();
        // 5. assert again the state of the system by examining the DB
        relinquishDB();        

        // etc.
    }

Some notes about them:

  • Tests are implemented with JUnit 3.8.2, but this is irrilevant to what will follow.
  • The application is a webapp implemented with a proprietary web framework.
  • Those tests are implemented running the servlet engine in process through ServletUnit.
  • The DB is interfaced through a proprietary framework and it is accessed behind a mock JDBC driver that works translating SQL statements in memory.
  • The state of the system is examined by fetching either an Entity or EntityList, abstract classes that represent respectively a single record or a collection of records in a table.
  • Methods connectDB() and relinquishDB() are used to manage the test connection, which needs to be different than the one used by the application for structural reasons.

All the tests that follow the above structure inherit from an abstract TestCase which implements its own setUp and tearDown, treated like template methods whose behaviour can be refined further (for example, choosing to install a different mock DB). connectDB() and relinquishDB() use connection parameters that are potentially established differently for every test, but in reality they are seamlessly copied over from test to test.

While this structure makes sense, I thought that repeating connectDB() and relinquishDB() several times in the test is extremely annoying. It would be nice if we can wrap some logic into a block that takes care of the repetition for us: calling connectDB() first, executing our code and then calling relinquishDB() in the end. If I was programming in ruby, that would have been extremely easy to implement with proper blocks, wouldn’t it be? Well, in java is not that difficult either, if you tolerate the syntactic noise of course. Let’s see how.

To start, we can define a Functor interface that can be used to implement a block without parameters:

public interface Functor<T> {
    T exec();
}

Now we need to wrap a bit of logic around it that takes care of connecting the DB and relinquishing it afterwards:

public class Fetcher {
    public static <T> T queryStateFor(Functor<T> f) {
        connectDB();
        T result = f.exec();
        relinquishDB();
        return result;
    }
    private static void connectDB() {
        // ...
    }
    private static void relinquishDB() {
        // ...
    }
}

The actual implementations of Fetcher.connectDB() and Fetcher.relinquishDB() are fairly trivial and the methods are in reality inlined: I’ve written them in a Compose Method style just to make them easier to understand and to trace back Fetcher structure to the test structure above.

The Fetcher can be used in the following way (assuming that it is imported statically in the test case):

    public void testSomething() throws Exception {
        // 1. istantiate the system
        // 2. interact with it through the UI
        final PurchaseOrder po = //...
        PurchaseOrderStatus status = queryStateFor(new Functor<PurchaseOrderStatus>() {
            public PurchaseOrderStatus exec() {
                return po.getLastStateChangeStatus();
            }
        });

        // etc.
    }

As you can see, this refactoring is not about saving keystrokes.

A developer was asking me which kind of advantage this style achieves over the other. In general, I think that functors are a powerful tool, often underestimated in statically typed languages like java. But these are the reasons why I think they are particularly relevant in the context of queries and tests:

  1. Avoid repeating connectDB(); … relinquishDB(); without the introduction of methods that would have to be rewritten for every test.
  2. Ensure that queries for checking purposes correctly connect to the proper DB and relinquish it in the end.
  3. Make the test more readable, without hiding relevant details (connecting and relinquishing the DB are irrelevant details to the test, only the query matters in the eyes of the reader / maintainer).
  4. In general, make the test less dependant upon lower level details whose relevance is marginal.
  5. Using a functor the query can be executed as a generified method, hence it definitely scores better in terms of type safety.

I’ve also thought about any disadvantage:

  1. The syntax looks a bit odd for the java world, but it’s not entirely a stranger.
  2. Current functor implementation can handle only one result per call, but it can certainly be extended and in general it doesn’t hurt significantly calling several functors in a row.

And you? What do you think about this way of handling a test connection to the DB?

PS: While I think that this style provides a better alternative to repeat calls to connectDB() and relinquishDB() all over the code, there’s actually a simpler way to solve the problem ==> the tests can be provided with their own connection that has nothing to deal with the connection handled by application code running in the servlet engine (credits to Mark for recognizing it). Nevertheless, functors are a powerful tool typically neglected in the java world and they definitely deserve more attention in situations like this one.

About these ads

Tags: , , , , , ,

4 Responses to “Using functors to handle test connections”

  1. Porter Says:

    Consider the Functor from the Commons…

    I’ve never been quite certain why it never really went anywhere – it’s been stuck in the Sandbox forever.

    http://commons.apache.org/sandbox/functor/

  2. thinkingbox Says:

    Porter,

    Yes, I concur, Commons Functor would be interesting, but I’m not sure about its status. Let’s hope for the better.

  3. Luca Minudel Says:

    I’ve tests like this in the code base I work with

    > tests can be provided with their own connection that has nothing to deal with the connection …
    I don’t understood this point, can you explain a bit more ?

    Agree about Functor, in C# with generics I can do something equivalent so I can re-use this idea :)

    my feedback about this:
    > tests that follow the above structure inherit from an abstract TestCase

    I’ve found hard to read the test code other then mine of tests case that inherits from a test base class (you point out an abstract – so this is not the case) – now I use composition and avoid inheritance for the tests classes

  4. thinkingbox Says:

    Luca,

    The tests that I’m dealing with are either HttpUnit tests that run in process with ServletUnit or various kind of unit tests which use a mock db driver instead of interfacing with the DB directly.

    We were able to migrate most of the tests to use their own connection, instead of hijacking the one used by the code running with the servlets. In a small number of cases though, the functor described above, that basically hijacks the connection being used by the servlet infrastructure, has been an effective way to simplify the tests.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 258 other followers

%d bloggers like this: