1# Adding a New Native Test: A Complete Example 2 3[TOC] 4 5If you are new to Android platform development, you might find this complete 6example of adding a brand new native test from scratch useful to demonstrate the 7typical workflow involved. 8 9Note that this guide assumes that you already have some knowledge in the 10platform source tree workflow. If not, please refer to 11https://source.android.com/source/requirements. 12 13In addition, if you are also unfamiliar with the gtest framework for C++, please 14check out its project page first: 15 16* https://github.com/google/googletest 17 18This guide uses the follow test to serve as an sample: 19 20* [Hello World Native Test](../../tests/example/native) 21 22It's recommended to browse through the code first to get a rough impression 23before proceeding. 24 25## Deciding on a Source Location 26 27Typically your team will already have an established pattern of places to check 28in code, and places to add tests. Most team owns a single git repository, or 29share one with other teams but have a dedicated sub directory that contains 30component source code. 31 32Assuming the root location for your component source is at `<component source 33root>`, most components have `src` and `tests` folders under it, and some 34additional files such as `Android.mk` (or broken up into additional `.mk` 35files). 36 37Since 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 40In some cases, your team might have further directory structures under `tests` 41due to the need to package different suites of tests into individual binaries. 42And in this case, you'll need to create a new sub directory under `tests`. 43 44To 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 62and here's a typical directory outline for components with multiple test source 63directories: 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 88Regardless of the structure, you'll end up populating the `tests` directory or 89the newly created sub directory with files similar to what's in `native` 90directory in the sample gerrit change. The sections below will explain in 91further details of each file. 92 93## Makefile 94 95Each new test module must have a makefile to direct the build system with module 96metadata, compile time dependencies and packaging instructions. 97 98[Latest version of the makefile](../../tests/example/native/Android.mk) 99 100A snapshot is included here for convenience: 101 102```makefile 103LOCAL_PATH := $(call my-dir) 104 105include $(CLEAR_VARS) 106 107LOCAL_SRC_FILES := \ 108 HelloWorldTest.cpp 109 110LOCAL_MODULE := hello_world_test 111LOCAL_MODULE_TAGS := tests 112 113LOCAL_COMPATIBILITY_SUITE := device-tests 114 115include $(BUILD_NATIVE_TEST) 116``` 117 118Some select remarks on the makefile: 119 120```makefile 121LOCAL_MODULE := hello_world_test 122``` 123 124This setting declares the module name, which must be unique in the entire build 125tree. It will also be used as the name as the binary executable of your test, as 126well as a make target name, so that you can use `make [options] <LOCAL_MODULE>` 127to build your test binary and all its dependencies. 128 129```makefile 130LOCAL_MODULE_TAGS := tests 131``` 132 133This setting declares the module as a test module, which will instruct the build 134system to generate the native test binaries under "data" output directory, so 135that they can be packaged into test artifact file bundle. 136 137```makefile 138LOCAL_COMPATIBILITY_SUITE := device-tests 139``` 140 141This line builds the testcase as part of the device-tests suite, which is 142meant to target a specific device and not a general ABI. 143 144```makefile 145include $(BUILD_NATIVE_TEST) 146``` 147 148This includes a core makefile in build system that performs the necessary steps 149to compile your test, together with gtest framework under `external/gtest`, into 150a 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 152other customizations, you should be able to find your test binary in: 153 154* `${OUT}/data/nativetest[64]/<LOCAL_MODULE>/<LOCAL_MODULE>` 155 156e.g. `${OUT}/data/nativetest[64]/hello_world_test/hello_world_test` 157 158And you will also find it: 159* ${OUT}/target/product/<target>/testcases/<LOCAL_MODULE>/<arch>/<LOCAL_MODULE> 160 161e.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 164Note: if the native ABI type of device is 64bit, such as angler, bullhead etc, 165the directory name will be suffixed with `64`. 166 167Please also note that currently the native tests in APCT does not support use of 168dynamically linked libraries, which means that the dependencies needs to be 169statically linked into the test binary. 170 171## Source code 172 173[Latest source code](../../tests/example/native/HelloWorldTest.cpp) 174 175Annotated source code is listed below: 176 177```c++ 178#include <gtest/gtest.h> 179``` 180 181Header file include for gtest. Note that the include file dependency is 182automatically resolved by using `BUILD_NATIVE_TEST` in the makefile 183 184```c++ 185#include <stdio.h> 186 187TEST(HelloWorldTest, PrintHelloWorld) { 188 printf("Hello, World!"); 189} 190``` 191 192gtests are written by using `TEST` macro: the first parameter is the test case 193name, and the second is test name; together with test binary name, they form the 194hierarchy 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 211For 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 217In order to simplify test execution, you also need write a test configuration 218file for Android's test harness, [TradeFederation](https://source.android.com/devices/tech/test_infra/tradefed/). 219 220The test configuration can specify special device setup options and default 221arguments to supply the test class. 222 223[LATEST TEST CONFIG](../../tests/example/native/AndroidTest.xml) 224 225A 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 240Some 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 249This tells TradeFederation to install the hello_world_test binary onto the target 250device using a specified target_preparer. There are many target preparers 251available to developers in TradeFederation and these can be used to ensure 252the 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 262This specifies the TradeFederation test class to use to execute the test and 263passes in the native test location that it was installed. 264 265Look here for more information on [Test Module Configs](test-config.md) 266 267## Build & Test Locally 268 269Follow these [Instructions](native.md) to build and execute your test 270