Considerations on Tests

Note: This document is a work in progress.

PowerMock

Avoid using PowerMock, if you can at all. It is black magic with special class loaders to mock static and what not really is a band aid for existing legacy code impossible to test. Consider refactoring the respective OpenDaylight code to be tested first, if you can.

Also think twice if you’re using PowerMock on existing utility classes - you may be testing at the wrong level. For example, many projects have utilities that deals with the DataBroker (that’s wrong, common shared utilities should be used). Many of these utility classes have static methods (that’s wrong, they should get a DataBroker passed to their constructor, see org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker, imagine there is no static there, that’s again just for legacy). When writing a test, you could be tempted to use PowerMock on such static utility methods. That’s wrong though - you should just let the code under test use such utilities - and use a test implementation of the DataBroker.

DataBroker

Typically you probably should not be mocking the DataBroker (using whatever framework), because there is a reasonably light weight test implementation of the entire persistence subsystem that is well suited for use in tests. You can easily use it by having your *Test class extends org.opendaylight.controller.md.sal.binding.test.ConstantSchemaAbstractDataBrokerTest and calling getDataBroker(), or just using the org.opendaylight.controller.md.sal.binding.test.DataBrokerTestModule static dataBroker() method.

NB that if you use the above, then (obviously) it makes no sense (anymore) to use @RunWith(MockitoJUnitRunner.class) and @Mock DataBroker and the transactions.

Mockito

Using Mockito can be fine - but keep an eye on how lines in your test are pure “Mockito infrastructure” related VS how many are “actually really test code”. Do not “over-mock”; for example, there is absolutely no point in mocking implementations of the interfaces YANG code generations used e.g. for RPC input & output objects - just use the *Builder, like “real” code would. Also of course you would never Mock something like e.g. a Future or an Optional (seen in existing ODL code!).

Use “normal” Java, with a hint of Mockito

Be careful not to overstretch usage of Mockito and write complicated to read many lines of Mockito to set up a series of Mock objects if you could achieve the same relatively simply using standard Java, perhaps using a simple anonymous inner class. For example, the following is perfectly fine to do something like this in a test, and probably more readable to most people looking at your test than the equivalent in Mockito:

YourRpcService testYourRpcService = new YourRpcService() {
    @Override Future<RpcResult<Output>> someOperation(Input input) {
        if ( ... input some condition ...) {
            return Futures.immediateFailedFuture(RpcResultBuilder.failed());
        }
    };
    ...
}

If YourRpcService has other methods than just someOperation(), you can use a variant of “partial mocking”:

import static org.opendaylight.yangtools.testutils.mockito.MoreAnswers.realOrException;

YourRpcService testYourRpcService = Mockito.mock(new YourRpcService() {
    @Override Future<RpcResult<Output>> someOperation(Input input) {
        if ( ... input some condition ...) {
            return Futures.immediateFailedFuture(RpcResultBuilder.failed());
        }
    }, realOrException());
    ...
}

Test Implementations of commonly used services

If several tests, or even other modules, are likely to use a stubbed service, then (only) it is worth to write something re-usable like this:

class abstract TestYourRpcService implements YourRpcService {
    public static YourRpcService newInstance() {
        return Mockito.mock(TestYourRpcService.class, realOrException());
    }
    @Override Future<RpcResult<Output>> someOperation(Input input) {
        ...
    }
    ...
}

Asserting Object structures

To assert the expected state of a tree of objects, typically but not necessarily data objects in Java objects generated by YANG binding, a number of projects use the vorburger/xtendbeans library.

The org.opendaylight.mdsal.binding.testutils.AssertDataObjects provides tight integration of this into OpenDaylight, including the org.opendaylight.mdsal.binding.testutils.XtendBuilderExtensions, which makes for a very readable syntax.

Component Tests

It’s not that hard to write Component Tests which test the interaction of a number of interrelated services, without going to a full blown and much “heavier” Karaf OSGi integration test just yet; see Component Tests (with Guice).

Integration Tests

Use Integration Tests (IT) to get a full Karaf OSGi runtime environment. TODO Simplify that…