
Bypass limitations in Calabash-Android with UIAutomator
- Transfer
Appium and Calabash are some of the most popular frameworks for automating the testing of Android applications. Each, of course, has its own advantages and disadvantages. Their main limitations are:
Calabash: can only control the user interface, which is part of the test application, in particular, there is no support for testing notifications;
- Appium: cannot call backdoor methods in applications like Calabash (these methods are very useful for setting the state of the application under test).
We at Badoo used Calabash to automate testing when Appium was just starting out. This is a very stable tool, and it is still faster than Appium, so we are not going to migrate. But in order to automate such a multifunctional application as Badoo, we had to bypass the Calabash restriction on working only with the test application interface.
Once we came to such a decision . And although it still works, its reliability is reduced due to many variations of devices with different diagonal, different versions of Android and so on.
In this article I will tell you how we solved the problem by adding UIAutomator2 support to Calabash. If you are too impatient, I’ll tell you a secret that at the end there is a link to a ready-to-use Ruby Gem.
Problem awareness
Let's take a look at the high-level architecture of Calabash-Android:
Calabash-Android-Server uses the Robotium framework, which in turn uses the Android Instrumentation framework to control the application. Instrumentation gives Robotium (and therefore Calabash) access to the runtime, which allows it to control the application interface and call methods from the outside.
But it also means that Robotium can only control the user interface that is part of the application code. Appium has no such restriction since it uses UIAutomator .
Solution
The Google Instrumentation framework is part of the Android helper library for testing . It works in the context of the application, shows all the interactions of the system with the application and, therefore, can manage them. Based on Instrumentation, such popular testing frameworks as Robotium and Espresso are built.
In addition, Robotium is used in the server side of Calabash-Android and therefore has access to Instrumentation information. Also, UIAutomator 2.0 became part of Instrumentation at the time, which makes it possible to use it inside the Calabash-Android server.
Using the CalabashInstrumentationTestRunner, the Ruby Calabash client launches Instrumentation via ADB. On a Calabash server, CalabashInstrumentationTestRunner is an extension of the Instrumentation Android class. This is an Instrumentation object passed to Robotium Solo. Thanks to UIAutomator 2, it can be used to create a new UIDevice object that is able to control the entire device.
This is how I came to the solution of the problem:
1) Added UIAutomator library to Calabash-Android server
I cloned the Calabash-Android-Server project and added the uiautomator2 JAR to the lib folder.
2) Installed the UIDevice object
In the file, InstrumentationBackend.java
I created a method for instantiating a UIDevice object from a UIAutomator.
public static UiDevice getUiDevice() {
if (instrumentation.getUiAutomation() == null) {
throw new NullPointerException("uiAutomation==null: did you forget to set '-w' flag for 'am instrument'?");
}
if(uiDevice == null) {
uiDevice = UiDevice.getInstance(instrumentation);
}
return uiDevice;
}
3) Added a new command using the UIAutomator2 API
It’s easy to add a new command to Calabash-Android-Server. All the commands that you use in Ruby code map into the Actions interface:
sh.calaba.instrumentationbackend.actions
Let's implement an action to open the notification panel:
public class PullNotification implements Action {
@Override
public Result execute(String... args) {
InstrumentationBackend.getUiDevice().openNotification();
return new Result(true);
}
@Override
public String key() {
return "pull_notification";
}
}
In this example, the key () method is used to name the command that will be used by the Calabash Ruby client. When the client invokes this command, it invokes the execute () method.
4) Started the measurement (Instrumentation) with the -w flag
Cloned the Ruby client from https://github.com/calabash/calabash-android . I patched lib/calabash-android/operations.rb
and added the -w flag to start the measurement using the ADB command. How to do this, you can see in this commit.
The above examples can be seen in my fork:
A working example:
Let's see how you can extend the notification panel and open one of them.
Clone both repositories from the above fork into a directory of the same level.
git clone
https://github.com/rajdeepv/calabash-androidgit clone
https://github.com/rajdeepv/calabash-android-serverIn both repositories, switch to the branch
‘uiautomator’
.Go to the ruby-gem folder in the calabash-android repository and build the Ruby Gem with the command
bundle exec rake build
.Include this gem in your project.
Change
start_test_server_in_background
tostart_test_server_in_background(with_uiautomator: true)
.The command notification bar pull:
perform_action('pull_notification')
.- To “touch” a notification with a known text fragment, use
perform_action('uiautomator_touch_partial_text', ‘my partial text')
Ready to use Ruby Gem:
Если не хотите всё это делать, можете скачать готовый gem и просто следовать трём последним пунктам.
Заключение
Мне потребовалось приложить некоторые усилия, чтобы углубиться в код Calabash-Android-Server, понять, как он работает, и исследовать возможность решения проблемы. С первой попытки это сделать не удалось, но в процессе работы я узнал некоторые секреты Instrumentation. Когда-нибудь я ими поделюсь с вами.
Хотя этот пример посвящён автоматизации push-уведомлений с помощью Calabash, тот же подход можно применить к любой задаче, с которой вы столкнётесь в автоматизационных фреймворках на базе Calabash:
тестирование виджетов вашего приложения для домашнего экрана;
обработка намерений (Intent) с помощью диалоговых блоков Complete action using в Android-приложениях;
- testing interaction with third-party applications running from your application.
I hope this post helps you in testing situations that go beyond working with the interface of your application using Calabash. If you have questions or any other feedback - welcome to comment.