Parameterized GTest for HAL testing

For a HAL interface, there might be multiple implementations. To test each instance for a HAL implementation, the standard way is to write a value-parameterized GTest.

Basic test setup

The GTest must inherit the base class testing::TestWithParam, of which the parameter is the name of each instance. In the SetUp method, the service can be instantiated based on the instance name, as shown in the following code snippet.

// The main test class for the USB hidl HAL
class UsbHidlTest : public testing::TestWithParam<std::string> {

 virtual void SetUp() override {
   usb = IUsb::getService(GetParam());
   ASSERT_NE(usb, nullptr);
...
 }

For each test method, use the macro TEST_P as shown in the following example:

TEST_P(UsbHidlTest, setCallback) {
...
}

Instantiate the suite with macro INSTANTIATE_TEST_SUITE_P, as shown in the following example:

INSTANTIATE_TEST_SUITE_P(
       PerInstance, UsbHidlTest,
       testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
       android::hardware::PrintInstanceNameToString);

The arguments are:

  1. InstantiationName, which can be anything that matches your test. PerInstance is a common name.

  2. The test class name.

  3. A collection of instance names, which can be retrieved from the built-in method, for example, getAllHalInstanceNames.

  4. The method to print the test method name. PrintInstanceNameToString is a built-in name you can use to compile a test name based on the instance name and test method name.

Test with multiple inputs

GTest supports tuples for value-parameterized tests. When a HAL test requires testing with multiple inputs (for example, a test with multiple interfaces), you can write a GTest with tuple as the test parameter. The complete code can be found in VtsHalGraphicsMapperV2_1TargetTest.

Compared to the GTest with a single test parameter, this test needs to use tuple as the test parameter as shown in the following example:

class GraphicsMapperHidlTest
   : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
 protected:
   void SetUp() override {
       ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
                                                                    std::get<1>(GetParam())));

}

If more complicated parameters are needed, it's recommended to use a structure and custom GTest ToString functions.

To instantiate the test suite, the macro INSTANTIATE\_TEST\_CASE\_P is also used, with two differences:

  • The third argument is a collection of tuples (versus a collection of strings in the basic case).
  • The method to compile a test name needs to support tuple. You can use the built-in method PrintInstanceTupleNameToString, which can handle tuples of strings, as shown in the following example:
INSTANTIATE_TEST_CASE_P(
       PerInstance, GraphicsMapperHidlTest,
       testing::Combine(
               testing::ValuesIn(
                       android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
           testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
       android::hardware::PrintInstanceTupleNameToString<>);