Skip to main content

Android "L" and UiAutomator command line shenanigans

Wow! It has been a long time since I've updated this blog; so long, in fact, that I a whole new version of Android has been announced (okay maybe 2 or 3). Like many of you, I was paying very close attention to the live streamed sessions at this year's Google I/O. At first I thought L contained nothing new for my QA interests but upon further digging I found a few tiny gems:


"You can execute shell commands from your instrumentation test with the new android.app.UiAutomation.executeShellCommand(). The command execution is similar to running adb shell from a host connected to the device. This allows you to use shell based tools such as dumpsys, am, content, and pm."


Oh that's nice.  I guess that means I don't need these anymore:
-     public static void runShellCommandStringArray(String[] command) throws IOException {
       try {..
-     public static void runShellCommandString(String command) throws IOException {
       try {...


My current project uses Google Tag Manager to provide packaged test configurations for use when launching the app so I'd been using these for launching the app via various intents depending on the test scenario. I'd also been using these to stop the app and clear it between test case executions in my setUp() and tearDown() calls to make sure that each test case can and will be run independently from a clean state.


Now, because reasons, I am planning on using this kind of trick to launch screenrecord and capture a video of the events in my UIAutomator tests, discarding the results for all passing tests and archiving test-case-method-named captures for all failed tests to allow for a sort of replay by testers and developers looking into the results from any given test runs (obviously this takes up space and carries the 3-minute limitation to screenrecord but none of my tests yet run 3 minutes or longer). When used in conjunction with “Show Touches” enabled in the developer settings, recording tests helps to debug failures by capturing exactly what happened from the user’s point of view, including all the steps leading up to the failure. My plan is to implement this in a similar fashion to the way that I previously implemented the screenshot on failed test routine found here in my post, Boom! Screenshot!


So let’s look at the specific code for how you can implement running shell commands from within your test cases. Then we’ll look at example calls to these commands in your test code given the scenarios I’ve described above. This gist is essentially a copy of some code I dug up on StackOverflow.com (whose URL I’ve lost or I’d reference it for further discussion if you wanted to follow up). I can’t recommend that resource highly enough for this kind of stuff. I mine it for gold regularly.





So as an example you might like to call am force-stop *com.yourappspackage.name* and pm clear *com.yourappspackage.name* during setUp() to ensure that each test starts from a clean slate. That would look like:

public void setUp() throws Exception {
super.setUp();
runShellCommandString(“/system/bin/am force-stop com.yourappspackage.name”);
runShellCommandString(“/system/bin/pm clear com.yourappspackage.name”);
}



And finally let’s say you want to start your test by launching your app via Google Tag Manager (like the cool kids do). That would look a little like this:

public void testLaunchWithGoogleTagDemo() throws UiObjectNotFoundException, IOException {
//Do cool stuff like set UiWatchers and other test prep


//Launch app using Google Tag Manager because we’re cool kids
String command = "/system/bin/am";
String subcommand = "start";
String action = "android.intent.action.VIEW";
String urlData = gtmUrl;
Log.d(LOG_TAG, "My gtmUrl is " + gtmUrl);
String flagData = "0x14000000";


String[] gtmLaunchStringArray = new String[] {command, subcommand, "-a", action, "-d", urlData, "-f", flagData, "-W" };


runShellCommandStringArray(gtmLaunchStringArray);


       ...
}


So those are some examples of how to use shell commands inside your test code and why doing so is sometimes useful. There are many other opportunities for awesomeness which is why Google have added support for it directly. Happy testing!

Comments

  1. This comment has been removed by the author.

    ReplyDelete
  2. This method cannot be used with the latest Uiautomator 2.0 correct? What can we do in 2.0 to clear cache and cookies before each test run?

    ReplyDelete
  3. Im able to run this command in Uiautomator 2.0...but it breaks with a "UiAutomation Disconnected" error when a UiWatcher kicks in...have you seen this problem?

    ReplyDelete

Post a Comment

Popular posts from this blog

UiAutomator and Watchers: Adding Async Robustness to UI Automation

"I'm looking over your shoulder... only because I've got your back." ~ Stephen Colbert After my recent UiAutomator review a user brought up an important question about the use of UiWatcher. The watchers serve as async guardians of the test flow, making sure the odd dialog window doesn't completely frustrate your tests. Having a tool that automatically watches your back when you're focused on the functional flow of your tests is awesome. 100% pure awesomesauce. Since the API documentation on watchers is scant and the UI Testing tutorial on the Android dev guide doesn't cover their use in depth, I figured I should add a post here that goes over a simple scenario demonstrating how to use this fundamentally important UI automation tool. In my example code below, I'm using uiautomator to launch the API Demo app (meaning run this against an Emulator built in API level 17 - I used the Galaxy Nexus image included in the latest ADT and platform tools).

UiAutomator.jar: What happened when Android's JUnit and MonkeyRunner got drunk and hooked up

"Drunkenness does not create vice; it merely brings it into view" ~Seneca So Jelly Bean 4.2 landed with much fanfare and tucked in amongst the neat new OS and SDK features (hello, multi-user tablets!) was this little gem for testers: UiAutomator.jar. I have it on good authority that it snuck in amongst the updates in the preview tools and OS updates sometime around 4.1 with r3 of the platform. As a code-monkey of a tester, I was intrigued. One of the best ways Google can support developers struggling with platform fragmentation is to make their OS more testable so I hold high hopes with every release to see effort spent in that area. I have spent a couple days testing out the new UiAutomator API  and the best way I can think of describing it is that Android's JUnit and MonkeyRunner got drunk and had a code baby. Let me explain what I mean before that phrase sinks down into "mental image" territory. JUnit, for all its power and access to every interface, e

Run-As Like the Wind: Getting private app data off non-rooted devices using adb run-as and a debuggable app

"You're some kind of big, fat, smart-bug aren't you?" ~Johnny Rico, Starship Troopers (1997) One of the most important things about writing bugs is making them descriptive but concise. Screenshots, video, debug logging, and hardware snapshots are all fairly standard or available to Android testers these days and can save you enormously on text when communicating what constitutes the bug. Sometimes though, the app gets into a weird state due to some transient data issue where you may not own the API or the complexity with forcing the app data into a certain state is prohibitively high. In those cases it is very handy to directly inspect the data the app has in its own directories. Getting at this data is trivial on emulators and rooted devices but due to file system permissions, this data is otherwise completely private to the app itself. If you're like me, you tend to test using devices rather than emulators and you probably prefer not to root your devices sin