“automate the impossible” blending the best of android … · “automate the impossible”...
TRANSCRIPT
Rajdeep Varma• Test Automation Engineer at Badoo• 8 Years into testing• Passionate about test automation with
mobile platforms• Author of open source utilities to
improve automation of mobile platforms
Hello, my name is
• Why we started with Calabash• Big limitation of Calabash: Important Business
cases could not be automated• Solution• Future with Calabash
Agenda
• 1000+ Stable Tests With Calabash• Fast (Compared to Appium!)• Integrated JaCoCo code coverage• Analytics testing• Some more magic!
Calabash @Badoo
public class LoginActivity extends Activity { public void foo() { // code to set some app state // Or seed DB before test // Or Disable ‘Rate Us’ popup } }
public class LoginActivity extends Activity { public void foo() { // code to set some app state // Or seed DB before test // Or Disable ‘Rate Us’ popup } }
foo() can be called from ruby code
def invoke_foo backdoor('foo')end
• Change App Locale• Change API URLs• Getting session_id from app• Disable “What’s new” tutorials after login
Where do we use Backdoors?
• Disable client side A/B tests• Clearing Cache• Faking SIM card for payments• Get Analytics data from app to validate it
Where do we use Backdoors?
Ruby-Client
http server
Instrumentation
Robotium
Command Executor
Why can’t Calabash drive whole device?
• Android’s testing support library• Runs in the application’s context• Exposes all the interactions the system has with
instrumented app
Instrumentation
First thing
• Extract UiAutomator2 jar from .aar file (Search inside sdk/extras/* for .aar)
• Add this jar as dependency in Calabash Server
adb shell am instrument -w com.badoo.mobile.test/sh.calaba.instrumentationbackend.CalabashInstrumentation
Calabash Instrumentation Test Runner
public class CalabashInstrumentation extends Instrumentation { @Override public void onCreate(Bundle arguments) { ... 1. Store the instrumentation object 2. Start http server and handle commands Main.start(AndroidInstrumentationStartup .Factory.newInstance(this, arguments)); ... } } This class is instantiated before
any of the application code
public class CalabashInstrumentation extends Instrumentation { @Override public void onCreate(Bundle arguments) { ... 1. Store the instrumentation object 2. Start http server and handle commands Main.start(AndroidInstrumentationStartup .Factory.newInstance(this, arguments)); ... } }
public class InstrumentationBackend { ... public static Instrumentation instrumentation; public static SoloEnhanced solo; ...}
instrumentation object used for creating Robotium driver
public class InstrumentationBackend { ... public static Instrumentation instrumentation; public static SoloEnhanced solo; ...}
Robotium driver instance.Can drive only App under test
public class InstrumentationBackend { ... public static Instrumentation instrumentation; public static SoloEnhanced solo; public static UiDevice uiDevice; ...}
Let’s Add a new instance of UiAutomator2 driver.This can drive whole device
public class InstrumentationBackend { ...
public static UiDevice getUiDevice() { if(uiDevice == null) { uiDevice = UiDevice.getInstance(instrumentation); } return uiDevice; }
...}
public class InstrumentationBackend { ...
public static UiDevice getUiDevice() { if(uiDevice == null) { uiDevice = UiDevice.getInstance(instrumentation); } return uiDevice; }
...}
public class InstrumentationBackend { ...
public static UiDevice getUiDevice() { if(uiDevice == null) { uiDevice = UiDevice.getInstance(instrumentation); } return uiDevice; }
...}
• Create PullNotification class
• Implement Action Interface
• Give our command a unique name
• Call the command from Ruby Client
public class PullNotification implements Action { ... }
Commands used in Ruby code are mapped to the “Action” Interface on Server side
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"; } }
Implement execute() from Action interface
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"; } }
Implement execute() from Action interface
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"; } }
key() is name of command to be used by the Ruby client
• Touch• FindElement• Expand Notifications• Clear Notifications• Dump Texts
Actions implemented so far
https://github.com/badoo/calabash-android-server
• https://techblog.badoo.com/blog/2017/01/24/break-limitations-with-calabash-android/
• https://developer.android.com/reference/android/app/Instrumentation.html• https://github.com/rajdeepv/calabash-android-server/tree/badoo_uiautomator• https://techblog.badoo.com/blog/2015/07/22/jacoco-coverage-in-cucumber-on-
android/• https://developer.xamarin.com/guides/testcloud/calabash/working-with/
backdoors/• https://techblog.badoo.com/blog/2014/10/09/calabash-android-query/• https://github.com/calabash/calabash-android• https://github.com/calabash/calabash-android-server
References