In-system testing re-invented

This post is about z2Unit an in-system, unit/integration testing enhancement to the z2-Environment.

What is it all about?

In software testing, as far tools are considered it all starts with Unit Testing. Unit testing translate into writing and running code that checks the behaviour and results of other code. Typically tests are executed out of context. That is, during testing, code that normally runs in the context of, say, a Web application is now executed on its own. Unit testing is extremely useful for code that is very algorithmic, needs to process possibly complex input in possibly complex ways.

The process of providing a functional environment to the tested code is called mocking. Unit testing stops being useful, when the effort to mock a required environment starts to outweigh the actual testing.

On the other end of the scale we find automated black-box integration testing where application behaviour is verified completely from the outside. In case of Web applications, tools like Selenium (just to name one of many) can be used. Black-box testing is extremely useful to make sure typical user flows are indeed still working. A fast-paced roll-out pipeline is practically unthinkable without this.

Now, there is a place in between those two that is highly interesting: In-system integration tests. These shine where unit tests stop being useful and where black box tests cannot reach into: Testing code in its real target environment without any limitation on verifying data changes or use of data types. In cases where code is highly integrated with the environment, this kind of test is less effort to write (and to follow up on refactorings) due to less mocking, and, as for black-box tests, it tells you more about the actual system behaviour in the real.

This is unlike so-called in-container testing, that essentially aims at simplifying the mocking effort by providing a complete (and yet specialized) application container as part of the mock.

Now what about z2Unit?

The idea behind z2Unit is to provide in-system tests based on the JUnit framework as conveniently as possible. In short: Just have a unit test class with all the usual features and all the expected life cycle instantiated within its Java component context. Fortunately this turns out to be relatively straightforward.

In principle JUnit works like this:

junit_plain

A client, say your IDE or some Build Tool like ANT or Maven, runs tests by invoking the JUnit Core. The JUnit Core in turn identifies which Runner to use. The Runner provides test meta data like what tests to run and in what order or filtering and eventually orchestrates the test execution during which test events are reported back to the core.

So there is actually a protocol between JUnit Core and the runner. Z2Unit uses this feature to remote the actual test execution using a custom runner on the client side:

z2unit

(click on the picture to enlarge). On the server-side any custom runner is supported. It is really all just about remoting the protocol. In fact, this is no new invention: When your IDE executes local tests, it does essentially the same.

This means:

  • For the client is all looks the same: IDE, ANT, Maven…
  • Running a server-side test is just a click in the IDE – you can actually use this to script the server-side

How to use it

If you want to try, the best way is to follow the How to Z2Unit.

Practically a test class looks like this:


@RunWith(Z2UnitTestRunner.class)
@Z2UnitTest(componentName="my_tests/java")
public class AZ2UnitTest {

    @Test
    public void someTestMethod() {
        Assert.assertTrue("This is just a test method",true);
    }
}

For an example of a custom runner, see Running Spock Tests with z2Unit and Groovy.

There is virtually no restriction on the server-side. An advanced test case may fully integrate with Spring injection and have an application context initialized before execution to be a first class application citizen (without any other effort). Here’s a slightly anonymized excerpt from real world test case:

@RunWith(Z2UnitTestRunner.class)
@Z2UnitTest(
    componentName="com.xyz.abc.vault",
    dependencies={"com.xyz.abc.vault/applicationContext"}
)
@Configurable
public class BitBillServiceIntegrationTest {

    @Autowired
    private ThisService bbs;
    @Autowired
    private ThatRepository repo;

    @Test
    @Transactional
    public void testStatesUpdateAndVerification() throws Exception {
...

Ok, so where are all the other in-system test frameworks?

Z2Unit is a piece of z2. If you have a look at the implementations (see here) you will notice that it is almost trivial. So how come there is no other in-system test frameworks? After all Cactus seems to have died a while back.

Why do people pull out big and complicated monster test-deploy-into-some-fake-test-container-with-more-mocking-than-sense guns?

In case you did actually try you will have noticed that z2Unit benefits enormously from system-centric approach of z2: What you see in your IDE is what is running in your local runtime. There is no other web app to deploy (z2Unit is part of the base distribution). There is nothing to configure and Eclipsoid will make sure your IDE has all the right types without investing any intelligence.

Hence I suppose it is the lack of lack of integratedness, the de-coupling of development approach from the execution environment that is sometimes a little blinding and makes people accept crazy detours.

References

  1. JUnit Framework
  2. How to z2Unit
  3. Running Spock Tests with z2Unit and Groovy