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…