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