Home | History | Annotate | Download | only in development
      1 # Adding a New Native Test: A Complete Example
      2 
      3 [TOC]
      4 
      5 If you are new to Android platform development, you might find this complete
      6 example of adding a brand new native test from scratch useful to demonstrate the
      7 typical workflow involved.
      8 
      9 Note that this guide assumes that you already have some knowledge in the
     10 platform source tree workflow. If not, please refer to
     11 https://source.android.com/source/requirements.
     12 
     13 In addition, if you are also unfamiliar with the gtest framework for C++, please
     14 check out its project page first:
     15 
     16 *   https://github.com/google/googletest
     17 
     18 This guide uses the follow test to serve as an sample:
     19 
     20 *   [Hello World Native Test](../../tests/example/native)
     21 
     22 It's recommended to browse through the code first to get a rough impression
     23 before proceeding.
     24 
     25 ## Deciding on a Source Location
     26 
     27 Typically your team will already have an established pattern of places to check
     28 in code, and places to add tests. Most team owns a single git repository, or
     29 share one with other teams but have a dedicated sub directory that contains
     30 component source code.
     31 
     32 Assuming the root location for your component source is at `<component source
     33 root>`, most components have `src` and `tests` folders under it, and some
     34 additional files such as `Android.mk` (or broken up into additional `.mk`
     35 files).
     36 
     37 Since you are adding a brand new test, you'll probably need to create the
     38 `tests` directory next to your component `src`, and populate it with content.
     39 
     40 In some cases, your team might have further directory structures under `tests`
     41 due to the need to package different suites of tests into individual binaries.
     42 And in this case, you'll need to create a new sub directory under `tests`.
     43 
     44 To illustrate, here's a typical directory outline for components with a single
     45 `tests` folder:
     46 
     47 ```
     48 \
     49  <component source root>
     50   \-- Android.mk (component makefile)
     51   \-- AndroidTest.mk (test config file)
     52   \-- src (component source)
     53   |    \-- foo.cpp
     54   |    \-- ...
     55   \-- tests (test source root)
     56       \-- Android.mk (test makefile)
     57       \-- src (test source)
     58           \-- foo_test.cpp
     59           \-- ...
     60 ```
     61 
     62 and here's a typical directory outline for components with multiple test source
     63 directories:
     64 
     65 ```
     66 \
     67  <component source root>
     68   \-- Android.mk (component makefile)
     69   \-- AndroidTest.mk (test config file)
     70   \-- src (component source)
     71   |    \-- foo.cpp
     72   |    \-- ...
     73   \-- tests (test source root)
     74       \-- Android.mk (test makefile)
     75       \-- testFoo (sub test source root)
     76       |   \-- Android.mk (sub test makefile)
     77       |   \-- src (sub test source)
     78       |       \-- test_foo.cpp
     79       |       \-- ...
     80       \-- testBar
     81       |   \-- Android.mk
     82       |   \-- src
     83       |       \-- test_bar.cpp
     84       |       \-- ...
     85       \-- ...
     86 ```
     87 
     88 Regardless of the structure, you'll end up populating the `tests` directory or
     89 the newly created sub directory with files similar to what's in `native`
     90 directory in the sample gerrit change. The sections below will explain in
     91 further details of each file.
     92 
     93 ## Makefile
     94 
     95 Each new test module must have a makefile to direct the build system with module
     96 metadata, compile time dependencies and packaging instructions.
     97 
     98 [Latest version of the makefile](../../tests/example/native/Android.mk)
     99 
    100 A snapshot is included here for convenience:
    101 
    102 ```makefile
    103 LOCAL_PATH := $(call my-dir)
    104 
    105 include $(CLEAR_VARS)
    106 
    107 LOCAL_SRC_FILES := \
    108   HelloWorldTest.cpp
    109 
    110 LOCAL_MODULE := hello_world_test
    111 LOCAL_MODULE_TAGS := tests
    112 
    113 LOCAL_COMPATIBILITY_SUITE := device-tests
    114 
    115 include $(BUILD_NATIVE_TEST)
    116 ```
    117 
    118 Some select remarks on the makefile:
    119 
    120 ```makefile
    121 LOCAL_MODULE := hello_world_test
    122 ```
    123 
    124 This setting declares the module name, which must be unique in the entire build
    125 tree. It will also be used as the name as the binary executable of your test, as
    126 well as a make target name, so that you can use `make [options] <LOCAL_MODULE>`
    127 to build your test binary and all its dependencies.
    128 
    129 ```makefile
    130 LOCAL_MODULE_TAGS := tests
    131 ```
    132 
    133 This setting declares the module as a test module, which will instruct the build
    134 system to generate the native test binaries under "data" output directory, so
    135 that they can be packaged into test artifact file bundle.
    136 
    137 ```makefile
    138 LOCAL_COMPATIBILITY_SUITE := device-tests
    139 ```
    140 
    141 This line builds the testcase as part of the device-tests suite, which is
    142 meant to target a specific device and not a general ABI.
    143 
    144 ```makefile
    145 include $(BUILD_NATIVE_TEST)
    146 ```
    147 
    148 This includes a core makefile in build system that performs the necessary steps
    149 to compile your test, together with gtest framework under `external/gtest`, into
    150 a native test binary. The generated binary will have the same name as
    151 `LOCAL_MODULE`. And if `tests` is used as `LOCAL_MODULE_TAGS` and there are no
    152 other customizations, you should be able to find your test binary in:
    153 
    154 *   `${OUT}/data/nativetest[64]/<LOCAL_MODULE>/<LOCAL_MODULE>`
    155 
    156 e.g. `${OUT}/data/nativetest[64]/hello_world_test/hello_world_test`
    157 
    158 And you will also find it:
    159 *    ${OUT}/target/product/<target>/testcases/<LOCAL_MODULE>/<arch>/<LOCAL_MODULE>
    160 
    161 e.g. ${OUT}/target/product/arm64-generic/testcases/hello_world_test/arm/hello_world_test
    162 &    ${OUT}/target/product/arm64-generic/testcases/hello_world_test/arm64/hello_world_test
    163 
    164 Note: if the native ABI type of device is 64bit, such as angler, bullhead etc,
    165 the directory name will be suffixed with `64`.
    166 
    167 Please also note that currently the native tests in APCT does not support use of
    168 dynamically linked libraries, which means that the dependencies needs to be
    169 statically linked into the test binary.
    170 
    171 ## Source code
    172 
    173 [Latest source code](../../tests/example/native/HelloWorldTest.cpp)
    174 
    175 Annotated source code is listed below:
    176 
    177 ```c++
    178 #include <gtest/gtest.h>
    179 ```
    180 
    181 Header file include for gtest. Note that the include file dependency is
    182 automatically resolved by using `BUILD_NATIVE_TEST` in the makefile
    183 
    184 ```c++
    185 #include <stdio.h>
    186 
    187 TEST(HelloWorldTest, PrintHelloWorld) {
    188     printf("Hello, World!");
    189 }
    190 ```
    191 
    192 gtests are written by using `TEST` macro: the first parameter is the test case
    193 name, and the second is test name; together with test binary name, they form the
    194 hierarchy below when visualized in result dashboard:
    195 
    196 ```
    197 <test binary 1>
    198 | \-- <test case 1>
    199 | |   \-- <test 1>
    200 | |   \-- <test 2>
    201 | |   \-- ...
    202 | \-- <test case 2>
    203 | |   \-- <test 1>
    204 | |   \-- ...
    205 | \-- ...
    206 <test binary 2>
    207 |
    208 ...
    209 ```
    210 
    211 For more information on writing tests with gtest, see its documentation:
    212 
    213 *   https://github.com/google/googletest/blob/master/googletest/docs/Primer.md
    214 
    215 ## Test Config
    216 
    217 In order to simplify test execution, you also need write a test configuration
    218 file for Android's test harness, [TradeFederation](https://source.android.com/devices/tech/test_infra/tradefed/).
    219 
    220 The test configuration can specify special device setup options and default
    221 arguments to supply the test class.
    222 
    223 [LATEST TEST CONFIG](../../tests/example/native/AndroidTest.xml)
    224 
    225 A snapshot is included here for convenience:
    226 ```xml
    227 <configuration description="Config for APCT native hello world test cases">
    228     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
    229         <option name="cleanup" value="true" />
    230         <option name="push" value="hello_world_test->/data/local/tmp/hello_world_test" />
    231     </target_preparer>
    232     <test class="com.android.tradefed.testtype.GTest" >
    233         <option name="native-test-device-path" value="/data/local/tmp" />
    234         <option name="module-name" value="hello_world_test" />
    235         <option name="runtime-hint" value="8m" />
    236     </test>
    237 </configuration>
    238 ```
    239 
    240 Some select remarks on the test configuration file:
    241 
    242 ```xml
    243 <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
    244     <option name="cleanup" value="true" />
    245     <option name="push" value="hello_world_test->/data/local/tmp/hello_world_test" />
    246 </target_preparer>
    247 ```
    248 
    249 This tells TradeFederation to install the hello_world_test binary onto the target
    250 device using a specified target_preparer. There are many target preparers
    251 available to developers in TradeFederation and these can be used to ensure
    252 the device is setup properly prior to test execution.
    253 
    254 ```xml
    255 <test class="com.android.tradefed.testtype.GTest" >
    256     <option name="native-test-device-path" value="/data/local/tmp" />
    257     <option name="module-name" value="hello_world_test" />
    258     <option name="runtime-hint" value="8m" />
    259 </test>
    260 ```
    261 
    262 This specifies the TradeFederation test class to use to execute the test and
    263 passes in the native test location that it was installed.
    264 
    265 Look here for more information on [Test Module Configs](../test-config.md)
    266 
    267 ## Build & Test Locally
    268 
    269 Follow these [Instructions](../native.md) to build and execute your test
    270