Write a host-driven test in Trade Federation

This page describes how to write a JUnit4-style device test driven by the host. This means that the host side of the harness is going to trigger actions against the device.

Note that we consider "host-side" tests and "host-driven" tests to be slightly different:

  • host-driven test: Is a test running on the host that interacts with one or more devices. The system under test (SUT) is not on the host itself but is being tested from the host.
  • host-side test: Is a test purely running on the host and testing something only on the host, for example unit tests.

Why create a host-driven test rather than an instrumentation test?

Some tests might require you to affect the device overall state, like issuing a reboot command. In the instrumentation test case, a reboot would kill the instrumentation, the test could not continue, and no results would be available.

Host-driven tests can also drive additional setup steps that require interaction with external devices on which the test depends on.

A host-driven test can handle these use cases and allow for advanced testing of the device with more scenarios. If you are in that situation, writing a host-driven test makes the most sense.

How are host-driven tests written in TF?

Here is a sample:

@RunWith(DeviceJUnit4ClassRunner.class)
public class SampleHostJUnit4DeviceTest extends BaseHostJUnit4Test {
    @Before
    public void setUp() throws Exception {
       // Some setup
    }

    @Test
    public void testCheckWeHaveDevice() throws Exception {
        Assert.assertNotNull(getDevice());
    }
}

Host-driven tests in Trade Federation are driven by the DeviceJUnit4ClassRunner JUnit4 test runner. The overall structure of the test class is the same as a regular JUnit4 test:

  • @BeforeClass
  • @Before
  • @Test
  • @After
  • @AfterClass
  • Assume, Assert

Extending BaseHostJunit4Test is a way to inherit useful testing utilities API such as:

  • installPackage: Allows to install an APK on the target device.
  • installPackageAsUser: Allows to install an APK as a user on the target device.
  • uninstallPackage: Allows to uninstall an APK.
  • isPackageInstalled: Check whether a package is installed or not.
  • hasDeviceFeature: Check whether device supports a feature or not. (pm list features)
  • runDeviceTests(DeviceTestRunOptions options): Run an instrumentation test against a target device using DeviceTestRunOptions to handle all the possible options.

Also provide access to the Tradefed device object:

  • getDevice(): Returns a TF device object for manipulating the device.
  • getBuild(): Returns a build info TF object to get information about the build.
  • getAbi(): Returns the ABI the test is running against.

Tradefed support: Per-class device preparation and clean up

JUnit4 @BeforeClass and @AfterClass are only applicable to static methods, which makes it impossible to use the #getDevice() handler to do some device-specific, one-time, per-class setup or clean up. To solve this issue, use the Tradefed annotation.

  • @BeforeClassWithInfo: Runs before @BeforeClass annotations
  • @AfterClassWithInfo: Runs after @AfterClass annotations
   @BeforeClassWithInfo
   public static void beforeClassWithDevice(TestInformation testInfo) {
       assertNotNull(testInfo.getDevice());
       testInfo.properties().put("mytest:test-prop", "test");
   }

   @AfterClassWithInfo
   public static void afterClassWithDevice(TestInformation testInfo) {
       assertNotNull(testInfo.getDevice());
       testInfo.properties().put("mytest:test-prop", "test");
   }

TestInformation allows you to use the device and store properties that can be used either in the static or non-static scope. BaseHostJUnit4Test supports getting the TestInformation in a non-static scope via #getTestInformation().

If you are not extending BaseHostJUnit4Test, you can implement ITestInformationReceiver in order to receive the TestInformation object.

How to configure a host-driven test in Tradefed?

In Tradefed XML configuration file, host-driven tests are run through the HostTest runner.

<test class="com.android.tradefed.testtype.HostTest" >
    <option name="class" value="android.sample.cts.SampleHostJUnit4DeviceTest" />
</test>