使用Robotium & UIAutomator构建基于twitter的测试

来源:互联网 发布:步步高录音电话软件 编辑:程序博客网 时间:2024/04/29 18:03

需翻墙] 原文地址:http://testdroid.com/testdroid/4737/using-twitter-app-as-an-example-how-to-build-robust-and-reliable-automated-tests


Using Twitter App as an Example: How to Build Robust and Reliable Automated Tests

Ville-Veikko Helppi

By Ville-Veikko Helppi
12 Jun 2013

What is the main difference between a successful and not-so-successful application or game available on Google Play? Sure, many things make a difference, but one great example is arcade car games. You can find hundreds – if not even thousands on Google Play. Why are some downloaded 100M+ times and some only thousands of times? Because of graphics? Gameplay? Features? Recommendations?

At the end of the day all of these are ‘nice-to-have’ characteristics for your application, but none of these are actually as important as robustness and reliability of that specific application on a range of different Android devices. ‘Crash’ and ‘not working’ are the most common feedback at Google Play for unstable applications/games, andthis makes the next hundred million users skip that lousy one.

In our second post in our series, “Deconstructing Mobile Testing Methods” , we’ll build a simple test case for one of the most used application on Android – theTwitter application. We’ll construct some basic test cases usingRobotium and uiautomator to illustrate how application can be tested and easily verified that it works on more than 200+ devices.

gplay_logo

BACK TO THE BASICS

For a reliable and continued success of application, developers should take testing more seriously, especially when their app will be targeted for global market. The localization of apps is very important and therefore, we’re swapping here for one of the most universal language for you guys, the Java.

Robotium

package com.bitbar.testdroid.test;// Array lists are the best choice if data has a known number of elements or// small fixed size upper bound. It automatically expands as data is added.import java.util.ArrayList;// Activity, a single focused thing that the user can do. Almost all activities// interact with the user, so Activity class takes care of creating a window.import android.app.Activity;// This class provides functional testing of a single activity.import android.test.ActivityInstrumentationTestCase2;// Basic building blocks for user interface with the widget packages.import android.view.View;import android.widget.EditText;import android.widget.TextView;// The Robotium Solo class – all-you-can-eat class for everythingimport com.jayway.android.robotium.solo.Solo;


The Robotium Solo is all-you-can-eat type of super class containing all the methods you need to test. It supports test cases that span over multiple activities, supports regular expressions and will automatically do user interface (UI) tricks when needed. Robotium Solo takes care of most expected new activities which requires less planning for test cases. Also, Robotium Solo can be used in parallel with ActivityInstrumentationTestCase2. The test cases are written from a user perspective and technical details are not needed.

twitter-bird-white-on-blue

uiautomator

// The UiDevice class provides access to state information about the device. This can be// also used to simulate user actions on the device, such as Home and Menu button pressesimport com.android.uiautomator.core.UiDevice;// Representation of user interface elementsimport com.android.uiautomator.core.UiObject;// Mechanism for tests to describe the UI elementsimport com.android.uiautomator.core.UiSelector;// UiDevice instance and UI test cases should extend this classimport com.android.uiautomator.testrunner.UiAutomatorTestCase;


The uiautomator API line-up is very straightforward, clean and simple while providing a versatile set of classes for developers to use. These classes, with interfaces and exceptions, allow developer to capture and manipulate UI components on the target application very easily.

PREPARATIONS AND CLASSES

In Robotium, ActivityInstrumentationTestCase2 class can be used to test several Activities. The ActivityInstrumentationTestCase2 allows use of the full Android system infrastructure and the functional tests for an activity can be written using this class. The communication with the Android infrastructure is done via the Instrumentation class which can be access via the getInstrumentation() method. ActivityInstrumentationTestCase2 starts the activity in the standard Android context, similar as if a user would start the application.

Robotium

// Named class extended with android.app.activitypublic class NewRobotiumTest extends ActivityInstrumentationTestCase2    // Static constant for launcher's activity classname    private static final String LAUNCHER_ACTIVITY_CLASSNAME = "com.twitter.android.StartActivity";    // The representation of ordinary class found in the class hiearchy    private static Class<?> launchActivityClass;    // Try-catches for com.bitbar.testdroid.test.NewRobotiumTest.    // LAUNCHER_ACTIVITY_CLASSNAME == com.twitter.android.StartActivity    static {        try {            launchActivityClass = Class.forName(LAUNCHER_ACTIVITY_CLASSNAME);        } catch (ClassNotFoundException e) {            throw new RuntimeException(e);    }    }    // Define Solo    private Solo solo;    // Let the compiler know what we are doing here    @SuppressWarnings("unchecked")    public NewRobotiumTest() {        super("com.twitter.android", (Class) launchActivityClass);    }    // Override annotations    @Override    public void setUp() throws Exception {        super.setUp();        solo = new Solo(getInstrumentation(), getActivity());    }    @Override    public void tearDown() throws Exception {    solo.finishOpenedActivities();        super.tearDown();    }    // Method used to find View specified by its id    protected View findViewById(String id) {        return findViewById(solo.getCurrentActivity().getResources().getIdentifier(id.replaceAll("\\.R\\.id\\.", ":id/"),                            null, null));    }    // Finds a view that was identified by the id attribute from the XML    protected View findViewById(int id) {        View view = solo.getView(id);        if (view != null)            return view;        ArrayList views = solo.getViews();        for (View v : views) {            if (v.getId() == id) {                return v;            }        }        return null;    }


The FindViewByID function provides an enhanced View finder. It first tries to find View from Activity, then from all Views under ViewRoot. For comparison, uiautomator doesn’t require much at this stage.

uiautomator

public class NewuiautomatorTest extends UiAutomatorTestCase

THE MAIN FUNCTIONS

One of the most interesting differences to developer using Robotium or uiautomator is the use of R class. The R class used in the Robotium example is a special class generated automatically at build time that provides user-accessible references to resources in terms of static, final constants of the R class. The R class is managed automatically by the Android plugin for Eclipse.

Screen Shot 2013-06-04 at 9

ROBOTIUM

// Public void for the operationpublic void testRecorded() throws Exception {    // Wait for the text 'Hello.' to be shown for newbie    if (solo.waitForText("Hello.")) {        // R class ID identifier for 'Sign in' - and click it            solo.clickOnView(findViewById("com.twitter.android.R.id.sign_in"));            // R class ID identifier for entering username            solo.enterText((EditText) findViewById("com.twitter.android.R.id.login_username"),"username");            // R class ID identifier for entering password            solo.enterText((EditText) findViewById("com.twitter.android.R.id.login_password"),"password");            // R class ID identifier for clicking log in            solo.clickOnView(findViewById("com.twitter.android.R.id.login_login"));            // Wait until log in is done            solo.waitForActivity("HomeTabActivity");        }        // Activate the text field to compose a tweet        solo.clickOnView((TextView) findViewById("com.twitter.android.R.id.menu_compose_tweet"));        // Type the tweet        solo.enterText((EditText) findViewById("com.twitter.android.R.id.edit"), "Testdroid is awesome!");        // Tweeting!        solo.clickOnView(findViewById("com.twitter.android.R.id.composer_post"));    }}


As mentioned, R.id is the dynamically generated class, created during the build process to dynamically identify all assets (from strings to widgets and layouts). Note that this R.id is Android-specific and doesn’t have much to do with Java language constructs.

The uiautomator, on the other hand, uses more descriptive, actual texts. What can be done with R classes in Robotium, can be done easily in uiautomator with resource IDs based on labels, texts, descriptions and so on.

uiautomator

// Public void for the operationpublic void testSignInAndTweet() throws Exception {    // Starting application:    getUiDevice().wakeUp();    // Press Home button to ensure we're at the beginning/homescreen    getUiDevice().pressHome();    // Select 'Apps' and click button    new UiObject(new UiSelector().description("Apps")).click();    // Select 'Twitter' and click button    new UiObject(new UiSelector().text("Twitter")).click();    // Locate and select 'Sign in'    UiSelector signIn = new UiSelector().text("Sign In");    // If button is available, click it    UiObject signInButton = new UiObject(signIn);    if (signInButton.exists()) {        signInButton.click();        // Set the username        new UiObject(new UiSelector().className("android.widget.EditText").instance(0)).setText("username");        // Set the password        new UiObject(new UiSelector().className("android.widget.EditText").instance(1)).setText("password");        // Click 'Sign in' button        new UiObject(new UiSelector().className("android.widget.Button").text("Sign In").instance(0)).click();        // Wait Sign in progress window        getUiDevice().waitForWindowUpdate(null, 2000);        // Wait for main window        getUiDevice().waitForWindowUpdate(null, 30000);    }    // Starting a new tweet:    new UiObject(new UiSelector().description("New tweet")).click();    // Typing text for a tweet    new UiObject(new UiSelector().className("android.widget.LinearLayout").instance(8)).setText("Awesome #Testdroid!");    // Tweeting!    new UiObject(new UiSelector().text("Tweet")).click();}


In order to take a screenshot of current window and store it as PNG Default scale of 1.0f (original size) and 90% quality is used. The screenshot is adjusted per screen rotation for both of the testing methods.

Robotium and uiautomator

// A screenshot of current window and store it as PNG
class.takeScreenshot("com.bitbar.testdroid.test.Test-Recorder-00X");

FINALLY, THE PERFORMANCE

Do not overlook the performance aspect of your mobile application lifecycle. Whether your application is native, web-based or hybrid, you need to test for performance on various devices, platforms and with various configurations to ensure optimal user experience for people downloading your application. Failing to address these aspects will inevitably result in brand degradation, business losses, and costly R&D iterations to fix.

We took these tests and ran those on more than 200 Android devices. Just at a glance, here are some results from two popular free devices atTestdroid Cloud, Sony Xperia Z C6303 and Alcatel One Touch 983:

Screen Shot 2013-06-11 at 9.38.44 AM

WHAT IS OUR CONCLUSION?

As shown in examples, both of these frameworks can do the job for Twitter application. But as applications are becoming more complex, the way more important question – again – is that how efficiently can those be used and how well those fit to your development and testing work. Well, that’s the topic we are diving into next week, so see you again right here! All comments are more than welcome!


原创粉丝点击