Break free from the instrumented test code — use ADB within the tests

Nikita Evdokimov
Kaspersky
Published in
7 min readJan 31, 2024

Introduction

My name is Nikita Evdokimov. I am an Android Developer on the Kaspersky Mobile Dev team. My teammates and I develop the Kaspresso test automation framework.

Sometimes the default android instrumental test tooling is not enough: test case could imply that the device’s Internet is off, brightness set to a certain level, network is slow etc. Most of these conditions could be easily set beforehand on the CI side, but what if you want to turn off the Internet during the test? Chances are that you would need to fall back to manual testing. Here, Kaspresso with an integrated ADB server comes to the rescue.

Table of contents:

1. Why use ADB in android tests?

2. How to execute ADB commands in the test

3. First approach

4. Port forwarding and ADB server

5. How to run ADB server

6. ADB server applications

6.1 Automatic artifacts pulling

6.2 Some sneak peek

7. Conclusion

1. Why use ADB in android tests?

Standard operations:

- push \ pull — files manipulation

- install \ uninstall — install additional APK, uninstall unwanted

- etc

ADB emu:

- call simulation

- fingerprint interaction

- slow Internet simulation

- set fake geo location

- etc.

2. How to execute ADB commands in the test

Espresso tests are white box tests. When you start an espresso test two APKs are installed on the test device: your app and test APK, which stores your test code. During the test run, a test APK communicates directly with your app using the native Android mechanisms. The host (your computer or the CI runner) only sends “start test” commands to the test device. The following communication between the host and the device stops up until the test is finished. Take a look at the figure below:

  1. Application is installed
  2. Test APK with the test code is installed
  3. Host sends a “launch test” command using ADB
  4. Test APK and application are communicating directly with each other

But there is an Appium which allows us to execute ADB commands in the test code

Yes, there is. Let’s take a look at how it does that. Appium installs only one APK — your app. Then Appium runs the test code on the host. It utilizes UIautomation to send commands to the app, so there’s no feedback — the app doesn’t communicate back. This results in the appium test being the black box ones.

  1. Application is installed
  2. Test script is executed
  3. Selenium starts. It executes UI interactions as if you test a web app
  4. Appium translates selenium’s commands into the uiAutomation ones
  5. Bootstrap executable is installed on the device. It works as a server listening to the appium’s commands
  6. Appium sends uiAutomation calls to the device

3. The first approach

Each emulator runs a router with a list of useful addresses. One of them is — 10.0.2.2. It redirects your request to the localhost of the computer, which runs the emulator. Our first try was to send requests to that address with ADB commands in the body. Simple python server would read them and execute them locally on the host.

Great! Is that it? Unfortunately, no. The thing played out nice until we encountered this line in the test case: “Turn off the Internet”. As you could probably guess, toggling the flight mode makes us lose access to the computer’s localhost. We need a new plan.

4. Port forwarding and ADB server

And there is one. There is an adb forward command in the documentation. Here is how it could be used:

- A server is started on the test device. Let’s say it works on the localhost:7100 address.

- Host executes adb forward tcp:6100 tcp:7100.

- After that when we connect to the localhost:6100 TCP port on the host side, we’re being redirected to the server on the device (working on the localhost:7100).

This channel works even if the Internet is turned off. In fact, ports are forwarded over the connection used for connecting a test device to the host: USB or WiFi.

There is an adb reverse command, which does the opposite — you could access the host’s localhost from the device, but it works only on android 5+, which was a bit high when the feature was developed.

We wrote a client, which should be started before the test run. It runs on the host while tests run on the device. There could be multiple devices. Let’s say, we have two of them. Let’s see how it works:

1. Test starts

2. We pick a port to host a server on the device. Let’s say it would be a localhost:8500

3. Host forwards a port to the device

adb -s device1 forward tcp:6100 tcp:8500

adb -s device2 forward tcp:48999 tcp:8500

Now, the host’s localhost:6100 could be used to send data to the device1, and the same for the localhost:48999 and device2.

4. Socket clients (on the host side) await for the server (on the device side) to accept their connection

5. Socket server is being started on the devices

After that the server (on the device) could send commands to the client (the host). The latter executes them and sends back the message that a command was executed, so the whole communication is synchronous (useful for long running commands like file transfer).

It’s important to note that the host was able to tell each device apart because from the device’s side, there’s only one connection — localhost:8500, but from the host point of view, each device’s localhost:8500 is mapped to a different port on the host (6100 and 48999 from the example above).

Another point to note is that an ADB server is capable of telling each device apart so we can connect as many of them as we like.

That’s it! Now we are able to execute ADB commands directly in the test code using ADB server running on the host. This concludes the theory behind ADB server. Let’s get to the practice!

5. How to run ADB server

ADB server is a part of a Kaspresso framework, which means that it has everything to support ADB server out of the box. You can get ADB server executable in the Kaspresso Github repository.

  1. Download adbserver-desktop.jar
  2. Run java -jar adbserver-desktop.jar

That’s it. To get more info on how to configure ADB server, go to the wiki page.

6. ADB server applications

Kaspresso has a handful of interfaces, which utilize ADB server to make your interaction with ADB easier. For example, instead of executing adbServer.performShell(“screencap -p somefile.png”), you could do device.screenshots.take(“screenshot_tag”).

Here’s a fraction of Kaspresso ADB wrappers:

Check out our Kaspresso wiki page for more cool interfaces allowing simple and human readable interaction with the Android OS.

6.1 Automatic artifacts pulling

Another great Kaspresso feature is automatic artifact pulling. Let’s say you took screenshots during the test, and you want to pull them from the device. In this case, people usually write shell scripts, which are being executed after the test run on the CI. With Kaspresso, you can simply tell which artifacts you want to pull and where to.

First, set KaspressoRunner as a test runner in your build.gradle file

Artifacts pulling configuration sample

artifactsRegex parameter tells which artifacts you want to pull and the destinationPath is a relative path to the ADB server executable. After the test is completed, ADB server will pull screenshots directly to the <adb-server-desktop.jar location>/output/artifacts directory.

6.2 A sneak peek

Another upcoming Kaspresso feature is automatic ADB server startup. This will allow you to automate things even further! Just set a flag in the gradle file, and after that Kaspresso will automatically run ADB server for you.

Conclusion

We’ve found out how ADB could be helpful for testing android apps, broke down how Kaspresso and ADB server solves the problem, checked out some of the useful ADB server and Kaspresso features, and peeked into Kaspresso’s future with automatic ADB server start up.

We hope you found this article useful. If so, check out Kaspresso Github project, leave a ⭐ and, of course, feel free to contribute to one of the best android testing frameworks.

For more learning materials and step-by-step guide, visit our tutorial and see the samples.

If you have any questions, please, feel free to join our discord.

And futhermore, we welcome you to read our previous publications about autotests on Android:

A step-by-step tutorial in codelab format for Android UI testing

How to make Espresso better ?

Happy coding!

--

--