2. Goals
► OpenDaylight’s Integration project looks at the overall system
test, in some ways treating the controller like a blackbox
► Developers write white-box test cases that enable different
types of test and verification that will tie up with Jenkins
2
3. JUnit
► JUnit is the most common testing framework used
► Can cover logic within a single bundle, or multiple bundles
Integrated with Maven through multiple plugins
Other mock framework (e.g., Mockito and EasyMock) make testing even
easier with creating mock objects pre-programmed with expectation
3
4. JUnit Basic Annotations
Annotation Description
@Test
public void method()
The @Test annotation identifies a method as a test method.
@Test (expected = Exception.class) Fails if the method does not throw the named exception.
@Test(timeout=100) Fails if the method takes longer than 100 milliseconds.
@Before
public void method()
This method is executed before each test. It is used to prepare the test
environment (e.g., read input data, initialize the class).
@After
public void method()
This method is executed after each test. It is used to cleanup the test
environment (e.g., delete temporary data, restore defaults).
@BeforeClass
public static void method()
This static method is executed once, before the start of all tests. It is used to
perform time intensive activities, for example, to connect to a database.
@AfterClass
public static void method()
This static method is executed once, after all tests have been finished. It is used
to perform clean-up activities, for example, to disconnect from a database.
@Ignore Ignores the test method. This is useful when the underlying code has been
changed and the test case has not yet been adapted. Or if the execution time of
this test is too long to be included.
4
5. Three Maven Testing Plugins
1. Unit tests with SureFire plugin
To verify if a certain feature is available
If test fails, build breaks right away
One maven goal:
► surefire:test
2. Integration tests with Fail-safe plugin
Test multiple components
Includes files with name IT*.java, *IT.java, *ITCase.java
If test fails, cleans up state in a post-integration-test phase, but does not fail the build
Two maven goals
► failsafe:integration-test runs the integration tests of an application
► failsafe:verify verifies that the integration tests of an application passed.
3. Integration tests with Pax-Exam plugin
Tests cross-bundle interfaces and integrates with OSGi
Can be used for spinning up virtual bundle container
5
6. JUnit Extended with Pax-Exam
► Spins up a test container with all dependencies injected
► Pax Exam JUnit test requires a method annotated with @Configuration
6
@RunWith(PaxExam.class)
public class SampleTest {
@Inject
private HelloService helloService;
@Configuration
public Option[] config() {
return options(
mavenBundle("com.example.myproject", "myproject-api", "1.0.0-SNAPSHOT"),
bundle("http://www.example.com/repository/foo-1.2.3.jar"),
junitBundles()
);
}
@Test
public void getHelloService() {
assertNotNull(helloService);
assertEquals("Hello Pax!", helloService.getMessage());
}
}
7. JUnit with Mockito
► In some cases, you don’t need to create a real object to test code.
► Using Mock objects Minimizes number of moving pieces tested
7
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
// assume there is a class MyDatabase
@Mock
MyDatabase databaseMock;
@Test
public void testQuery() {
// assume there is a class called ClassToTest
// which could be tested
ClassToTest t = new ClassToTest(databaseMock);
// call a method
boolean check = t.query("* from t");
// test the return type
assertTrue(check);
// test that the query() method on the
// mock object was called
Mockito.verify(databaseMock).query("* from t");
}
}
8. A more Concrete ODL example:
controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest
8
public class TopologyLinkDataChangeHandlerTest {
NetworkGraphService networkGraphService;
DataBrokerService dataBrokerService;
DataChangeEvent dataChangeEvent;
Topology topology;
Link link;
@Before
public void init() {
networkGraphService = mock(NetworkGraphService.class);
dataBrokerService = mock(DataBrokerService.class);
dataChangeEvent = mock(DataChangeEvent.class);
link = mock(Link.class);
topology = mock(Topology.class);
}
@Test
public void testOnDataChange() throws Exception {
TopologyLinkDataChangeHandler topologyLinkDataChangeHandler = new
TopologyLinkDataChangeHandler(dataBrokerService, networkGraphService, 2);
Map<InstanceIdentifier<?>, DataObject> original = new HashMap<InstanceIdentifier<?>, DataObject>();
when(dataChangeEvent.getOriginalOperationalData()).thenReturn(original);
InstanceIdentifier<?> instanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier("flow:1");
Map<InstanceIdentifier<?>, DataObject> updated = new HashMap<InstanceIdentifier<?>, DataObject>();
DataObject dataObject = mock(DataObject.class);
updated.put(instanceIdentifier, dataObject);
when(dataChangeEvent.getUpdatedOperationalData()).thenReturn(updated);
when(dataBrokerService.readOperationalData(instanceIdentifier)).thenReturn(topology);
List<Link> links = new ArrayList<>();
links.add(link);
when(topology.getLink()).thenReturn(links);
topologyLinkDataChangeHandler.onDataChanged(dataChangeEvent);
Thread.sleep(2100);
verify(networkGraphService, times(1)).addLinks(links);
}
Setup data
Setup mock objects
Exercise
Verify
9. Sonar Code Coverage
► Sonar picks up testing results by using the JaCoCo plugin
► http://sonar.opendaylight.org/dashboard/index/45745?metric=it_coverage
9