Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Unit tests for ONOS are built using the JUnit framework, version 4.12. Unit tests are used to verify correctness of implementations and are run as part of every full build of ONOS. The nightly SonarQube build runs all of the unit tests and produces coverage data that can be seen here.

Table of Contents

How to Write Good Tests

Unit tests should be as short, fast, and reliable as they can be.  Every developer on the project will be running your tests, they should be easy to run and produce accurate results. Here are some key ways to write tests that are not brittle:

  • Avoid using sleep() whenever possible, since it often leads to brittle tests.  If you find that you have to wait for an event or wait for some work to be done by another thread, prefer latches or thread notifications to sleeps.
  • Try to keep individual tests small, and only test one thing per test.
  • Use mocking when you need to include a complicated service to satisfy dependencies. ONOS uses the EasyMock framework, version 3.4.
  • Maven Bazel may choose to run multiple tests in the same Java virtual machine.  If you use static variables in classes, be sure to reset them to known starting values before each test runs.
  • Do not use local resources like files and , ports, or IP Addresses in tests.

Basic Tests

...

A basic test for each one of your constructors and a check for the values returned by data access methods should always be included.

 

Code Block
languagejava
titleConstructor and Accessor Check
    /**
     * Checks the construction of a FlowId object.
     */
    @Test
    public void testConstruction() {
        final long flowIdValue = 7777L;
        final FlowId flowId = FlowId.valueOf(flowIdValue);
        assertThat(flowId, is(notNullValue()));
        assertThat(flowId.value(), is(flowIdValue));
    }

...

Code Block
languagejava
titleAccessing Private Data in a Test
import org.onlab.junit.TestUtils;
 
    @Test
    public void testLeaderEvents() throws Exception {
        final ObjectiveTracker tracker = new ObjectiveTracker();

        final SetMultimap<LinkKey, IntentId> intentsByLink =
                TestUtils.getField(tracker, "intentsByLink");
        assertThat(intentsByLink.size(), is(0));
    }

...

Mocking

Mocking is a useful strategy for limiting the interaction between your code under test and other modules that are required to satisfy dependencies.  There are several strategies that may be used for mocking, two that are used inside of ONOS are described here.

...

Code Block
languagejava
titleCustom Mock Example
   private static class TestIntentCompilerError implements IntentCompiler<Intent> {
        @Override
        public List<Intent> compile(Intent intent, List<Intent> installable,
                                    Set<LinkResourceAllocations> resources) {
            throw new IntentCompilationException("Compilation always fails");
        }
    }
 
    /**
     * Tests for proper behavior of installation of an intent that triggers
     * a compilation error.
     */
    @Test
    public void errorIntentCompile() {
        final TestIntentCompilerError errorCompiler = new TestIntentCompilerError();
        final IntentManager intentManager = new IntentManager();
        final IntentExtensionService extensionService = intentManager;
        final IntentService intentService = intentManager;

        extensionService.registerCompiler(MyIntent.class, errorCompiler);
        MyIntent intent = new MyIntent();
 
		// Invoke the error compiler
		intentService.submit(myIntent);
    }

 

Hamcrest

Hamcrest is a powerful framework for defining matchers for data values in tests. ONOS uses version 1.3 of Hamcrest. Contributors are encouraged to learn about and use the Hamcrest framework, particularly when working with arrays and collections. Hamcrest also gives you the ability to write your own matchers, which will make your tests easier to read and easier to extend by other developers.

Here is an example of a custom Hamcrest matcher, that matches a Criterion type in a TrafficSelector object:

Code Block
languagejava
titleHamcrest Matcher for Criterion Type
    /**
     * Hamcrest matcher to check that a selector contains a
     * Criterion with the specified type.
     */
    public static final class CriterionExistsMatcher
           extends TypeSafeMatcher<TrafficSelector> {
        private final Criterion.Type type;
        /**
         * Constructs a matcher for the given criterion type.
         *
         * @param typeValue criterion type to match
         */
        public CriterionExistsMatcher(Criterion.Type typeValue) {
            type = typeValue;
        }
        @Override
        public boolean matchesSafely(TrafficSelector selector) {
            final Set<Criterion> criteria = selector.criteria();
            return notNullValue().matches(criteria) &&
                   hasSize(1).matches(criteria) &&
                   notNullValue().matches(selector.getCriterion(type));
        }
        @Override
        public void describeTo(Description description) {
            description.appendText("a criterion with type \" ").
                    appendText(type.toString()).
                    appendText("\"");
        }
    }

    /**
     * Creates a criterion type matcher.  Returns a matcher
     * for a criterion with the given type.
     *
     * @param type type of Criterion to match
     * @return Matcher object
     */
    @Factory
    public static Matcher<TrafficSelector> hasCriterionWithType(Criterion.Type type) {
        return new CriterionExistsMatcher(type);
    }
 
   /**
     * Tests the builder functions that add specific criteria.
     */
    @Test
    public void testCriteriaCreation() {
        TrafficSelector selector;

        selector = DefaultTrafficSelector.builder()
                .matchInport(PortNumber.portNumber(11)).build();
        assertThat(selector, hasCriterionWithType(Type.IN_PORT));
    }

Home : Contributing to the ONOS Codebase

...

Add library for Unit Test

If you are using a library for Unit Test other than the above, please add the library to the build path. You can modify the lib/deps.json file where we keep track of external libraries:

Code Block
languagebash
titleModify the lib/deps.json file
vi lib/deps.json
Code Block
titlelib/deps.json
{
 "libraries": {
・・・
,
    "TEST": [
      "[new library name]",
      "junit",
      "easymock",
      "hamcrest-all",
      "hamcrest-optional",
      "guava-testlib",
      "//utils/junit:onlab-junit"
    ],
・・・
 },


 "artifacts": {
・・・
    "jsch":"mvn:com.jcraft:jsch:0.1.53",
    "[new library name]":"mvn:[new library path]:[new library version]",
    "junit":"mvn:junit:junit:4.12",
    "junit-dep":"mvn:junit:junit:4.10",
・・・
 }
}

...and then run onos-lib-gen tool to re-generate the Bazel workspace file.

Code Block
languagebash
titleRe-generate Bazel workspace
tools/build/onos-lib-gen



...

Home : Contributing to the ONOS Codebase

...