1. Overview

In this tutorial, we'll investigate how we can monitor unit tests using JUnit test rules. JUnit provides the TestWatcher class as a template to cover this kind of needs. In the end, we'll have a basic monitoring rule using the TestWatcher class.

2. Quick Look at TestWatcher

Let's first look at the TestWatcher class.

In essence, TestWatcher defines several hooks for capturing execution phases of a test. We can think of hooks as methods meant to be overridden by subclasses. As a result, a subclass can put its own logic to the existing process.

public Statement apply(final Statement base, final Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                List<Throwable> errors = new ArrayList<Throwable>();

                startingQuietly(description, errors);
                try {
                    base.evaluate();
                    succeededQuietly(description, errors);
                } catch (@SuppressWarnings("deprecation") org.junit.internal.AssumptionViolatedException  e) {
                    errors.add(e);
                    skippedQuietly(e, description, errors);
                } catch (Throwable e) {
                    errors.add(e);
                    failedQuietly(e, description, errors);
                } finally {
                    finishedQuietly(description, errors);
                }

                MultipleFailureException.assertEmpty(errors);
            }
        };
    }

Here, the apply() method shows general flow and hooks. As we can see, we have starting, succeeded, skipped, failed, and finished hooks.

3. Implementing Test Rule using TestWatcher

MonitorRule is a TestRule extending TestWatcher. Moreover, it overrides the previously mentioned methods. Although it simply prints some messages, it shows that we can monitor the execution of our tests.

public class MonitorRule extends TestWatcher {

    /**
     * Invoked when a test succeeds
     */
    @Override
    protected void succeeded(Description description) {
        System.out.printf("%s succeeded%n", description.getMethodName());
    }

    /**
     * Invoked when a test fails
     */
    @Override
    protected void failed(Throwable e, Description description) {
        System.out.printf("%s failed with %s%n", description.getMethodName(), e);
    }

    /**
     * Invoked when a test is skipped due to a failed assumption.
     */
    @Override
    protected void skipped(AssumptionViolatedException e, Description description) {
        System.out.printf("%s skipped%n", description.getMethodName());
    }

    /**
     * Invoked when a test is about to start
     */
    @Override
    protected void starting(Description description) {
        System.out.printf("%s is starting%n", description.getMethodName());
    }

    /**
     * Invoked when a test method finishes (whether passing or failing)
     */
    @Override
    protected void finished(Description description) {
        System.out.printf("%s finished%n", description.getMethodName());
    }
}

4. Summary

In this tutorial, we've seen how to implement a custom test rule.

As always, the source code for all samples is available on Github.