Running Android Tests in Docker

Running Android Tests in Docker

In this article, you'll learn how to run and test their automated Android mobile application tests in a Docker container.

In this article, you'll learn how to run and test their automated Android mobile application tests in a Docker container.

As part of the project I’m currently engaged on, my team is writing automated tests for an application which has a web interface, and also two mobile apps, one for Android, and one for iOS. As part of the project, we’ve built a test automation pipeline which runs our tests against our application to ensure changes we’re making don’t impact other tests. Yes, we’re testing our tests. One of the challenges we ran into was ensuring we could verify our Android and iOS tests still worked in a timely fashion. The solution we eventually found worked best was to create our own emulators inside of a Docker container to test on.

The Setup

If you’re not familiar with Docker, check out some of our many excellent posts on it. It also works great for testing. Essentially, instead of spinning up a web application inside a container, we wanted to spin up an Android emulator, running our app. We would then connect to the container, the same way we would a tethered physical device, a local emulator, or something in the cloud. This made it incredibly cheap (and fast) to parallelize our testing. All we needed to do was launch multiple Docker containers, and then connect using ADB to each one.

The Dockerfile

Unfortunately, building the Docker container wasn’t straightforward. We needed a Docker container with Android SDK installed, an Android VM created, and Appium. Because I had gotten everything running just fine locally (Ubuntu), I decided to start with a similar base image (maven:3.5.2-jdk-8). We then installed the ADK, set up the emulator, and installed Appium. Finally, we coped over the APK and test suite. We soon discovered that the base image didn’t have kvm set up, so we needed to enable this. Not an easy task, which unfortunately required a manual step. As a result, I decided to split this into two Docker files, a new base one with kvm setup, and one with all of the installs.


This Docker container was relatively straightforward, however, not quite simple. I built it once, uploaded it to my local Docker repository, and then built on top of it for the Docker Android container. All I did was install kvm, and manually copy over the proper lib modules. The Dockerfile looked like:

FROM maven:3.5.2-jdk-8
#debian based

RUN apt-get update -qqy \
    && apt-get -qqy install libglu1 qemu-kvm libvirt-dev virtinst bridge-utils msr-tools kmod \
    && wget -q \
    && dpkg -i cpu-checker_0.7-0ubuntu7_amd64.deb \
    && apt-get install -f \
    && kvm-ok

From there, I built and tagged the Docker file. I then ran it, logged in (-it), and copied over my machine’s lib modules (/lib/modules). Please note, your mileage might vary based on your machine’s kernel and version. Then I pushed this image into my local Docker repository.


This Docker container had a lot more steps, but ultimately wasn’t too much more complex. I set up my Android SK, loaded up my emulator, installed Appium, and copied over our APK and tests. The Dockerfile looked like this:

FROM kvm:maven-3.5.2-jdk-8#tag we gave to DockerfileKVM
# debian based


# Install android sdk

# install adk
RUN mkdir -p /opt/adk \
    && wget -q${ANDROID_SDK_VERSION}.zip \
    && unzip sdk-tools-linux-${ANDROID_SDK_VERSION}.zip -d /opt/adk \
    && rm sdk-tools-linux-${ANDROID_SDK_VERSION}.zip \
    && wget -q \
    && unzip -d /opt/adk \
    && rm \
    && yes | /opt/adk/tools/bin/sdkmanager --licenses \
    && /opt/adk/tools/bin/sdkmanager "emulator" "build-tools;${BUILD_TOOLS}" "platforms;${ANDROID_PLATFORM}" "system-images;${ANDROID_PLATFORM};google_apis;armeabi-v7a" \
    && echo no | /opt/adk/tools/bin/avdmanager create avd -n "Android" -k "system-images;${ANDROID_PLATFORM};google_apis;armeabi-v7a" \
    && mkdir -p ${HOME}/.android/ \
    && ln -s /root/.android/avd ${HOME}/.android/avd \
    && ln -s /opt/adk/tools/emulator /usr/bin \
    && ln -s /opt/adk/platform-tools/adb /usr/bin

# Install latest nodejs, npm, appium

# install appium
RUN wget -q${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz \
    && tar -xJf node-${NODE_VERSION}-linux-x64.tar.xz -C /opt/ \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/npm /usr/bin/ \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/node /usr/bin/ \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/npx /usr/bin/ \
    && npm install -g [email protected]${APPIUM_VERSION} --allow-root --unsafe-perm=true \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/appium /usr/bin/

EXPOSE [4723,2251,5555]
CMD [""]

What you’ll notice is there was one last piece to this puzzle, the docker-entrypoint, which we used to launch the emulator, and get everything connected with Appium. This luckily was pretty easy, once you knew what to do.


# launch the emulator
exec /opt/adk/tools/emulator -avd Android -no-audio -no-window &

# setup appium
while [ -z $udid ]; do
    udid=`adb devices | grep emulator | cut -f 1`
exec appium -p 4723 -bp 2251 --default-capabilities '{"udid":"'${udid}'"}' &

And that was it, all we needed to do, was launch our tests.

Test Execution

Without getting into the specifics of the project, we could do that either locally, or through another Docker container, but the simplest way was definitely locally, using Maven. We could do this by simply specifying the Docker IP, the same way you would if you have the emulator running locally, or the device tethered. Swapping ports is simple enough as well.

Final Thoughts

We did run into one last issue, which was trying to run this all in AWS. We’ve been trying to keep our pipelines as fast moving as possible, and a large portion of that means dynamically provisioned machines in AWS when we need them, it greatly increased our throughput. Unfortunately, AWS machines don’t support nested KVM (yes, I’m aware of using metal, but we wanted to avoid that cost increase). Unfortunately, that meant a large portion of this couldn’t be used in this fashion. Stay tuned for the next blog post, in which I get into the work around to solve this issue.

Find this useful? Got stuck? As always, please leave some comments below.

Learn More

An illustrated guide to Kubernetes Networking

AWS DevOps: Introduction to DevOps on AWS

Getting started with Flutter

Android Studio for beginners

Building a mobile chat app with Nest.js and Ionic 4

Creating an iOS app with user presence using Node.js and Swift

Let’s Develop a Mobile App in Flutter

Docker Tutorial for Beginners

Docker Basics: Docker Compose

Docker and Kubernetes: The Complete Guide

Docker Mastery: The Complete Toolset From a Docker Captain

Docker for the Absolute Beginner - Hands On - DevOps

Learn DevOps: The Complete Kubernetes Course

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

Brave, Chrome, Firefox, Opera or Edge: Which is Better and Faster?

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

WordPress in Docker. Part 1: Dockerization

This entry-level guide will tell you why and how to Dockerize your WordPress projects.

List all containers in Docker(Docker command)

We can get a list of all containers in docker using `docker container list` or `docker ps` commands.

Android App Development Company in UAE

Have a plan to build an robust Android App Development with multiple features? We at Data EximIT is one of the best **[Android App Development Company in UAE]( "Android App Development...