Versions Compared

Key

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

A UnitTest in Geode is a test with very narrow and well defined scope. Any complex dependencies and interactions are stubbed or mocked.

  • Should use JUnit 4 or JUnit Jupiter (aka JUnit 5) syntax
  • File name ends with *Test
  • Should use Category annotation of type UnitTestbe part of the test source set folder (<geode-module-dir>/test/java)
  • Should complete in milliseconds 
  • Should generally test a single class
  • Typically uses white-box testing, uses Mocks/Fakes and helps guarantee internal quality (quality of code and class design)
  • Follows "A Set of Unit Testing Rules" by Michael Feathers
    • A UnitTest should not do any of the following:
      • communicate with a database
      • communicate across the network
      • access the file system
      • prevent the running of other unit tests in parallel
      • require anything special in the environment (such as editing config files or running an external process)

...

It's not absolutely necessary to introduce a new *RegressionTest class for covering a bug. If new regression test coverage fits better within an existing test class, then add one or more new tests to that existing test class but include javadocs on the new test methods which includes the GEODE JIRA ticket number and its summary at a minimum.

Preferred Testing Frameworks and Libraries Appropriate for Geode UnitTests

Overall Framework

  • JUnit 4 (including Rules) or JUnit Jupiter (which does not support Rules)
  • Paramerized – JUnit 4.12 has a bug which prevents Parameterized and Category from working together properly
    • Please use CategoryWithParameterizedRunnerFactory from Geode when using Parameterized (see GEODE-1350)

Assertion Library

  • AssertJ – richer API with better failure messages than JUnit 4 Assert

Mocking Library

  • MockitoPowerMock – use this as a last resort – refactoring code to facilitate better testing is preferred

Expected Exceptions

  • Use AssertJ or Catch-Exception instead of JUnit 4 Rule ExpectedException
  • AssertJ (assertThatThrownBy) – this is the cleanest and preferred way to test for expected exception
  • Catch-Exception – better support for complex nesting of exceptions or exceptions with unusual APIs

Additional 3rd Party Libraries for UnitTests

  • JUnitParams – provides test method parameterization (usually better to use than JUnit 4 Parameterized)
  • System Rules – powerful set of JUnit 4 Rules
  • Awaitility* – useful for awaiting asynchronous conditions

(*=Concurrency frameworks or rules are typically more appropriate for IntegrationTests)

Custom Geode JUnit 4 Rules and Testing Tools

  • RestoreLocaleRule – restores JVM to original Locale
  • RestoreTCCLRule – restores Thread Context Class Loader
  • ExecutorServiceRule* – provides ExecutorService for concurrent testing

(*=Concurrency frameworks or rules are typically more appropriate for IntegrationTests)

Examples of actual tests

Examples of some good UnitTests:

...

Code Block
package org.apache.geode.internal.cache.control;
 
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.test.junit.categories.UnitTest;

@Category(UnitTest.class)
public class RebalanceTaskTest {
 
  private RebalanceTask rebalanceTask;
  private RebalanceStats rebalanceStats;
 
  @Before
  public void setUp() {
    // arrange: create the SUT (system under test) and its dependencies
    rebalanceStats = mock(RebalanceStats.class);
    rebalanceTask = new RebalanceTask(rebalanceStats);
  }
 
  @After
  public void tearDown() {
    // cleanup anything that might affect a later test or that uses any resources
  }
 
  @Test
  public void execIncrementsRebalanceStats() throws Exception {
    // act: do something like invoke exec
    // assert: assertThat expected behavior or interaction with dependency occurred
  }
}

 

...