Robotium Automated Testing

Source: Internet
Author: User

Robotium Automation test One, Setup

In the Android studio environment, under the Build.gradle file of the module you want to test, add

Compile ' com.jayway.android.robotium:robotium-solo:5.4.1 '

And then sync down.

Second, Start

Robotium is the encapsulation of the instrumentation framework method, so you need to inherit the test class, rewrite the constructor, the SetUp (), and the Teardown () method before using.

public class SplashActivityTest extends ActivityInstrumentationTestCase2 {    private Solo solo;    public SplashActivityTest() throws ClassNotFoundException {        super(SplashActivity.class);    }    @Override    public void setUp() throws Exception {        super.setUp();        solo = new Solo(getInstrumentation());        getActivity();    }    @Override    public void tearDown() throws Exception {        solo.finishOpenedActivities();        super.tearDown();    }}

The ACTIVITYINSTRUMENTATIONTESTCASE2 test class is inherited. The ACTIVITYINSTRUMENTATIONTESTCASE2 test class is primarily used for cross-activity testing. (The relationship and architecture of the test class is attached to page 1)

which
solo = new Solo(getInstrumentation());

solo.finishOpenedActivities();is unique to the Robotium framework.

The test method must be public and begin with test. This is because the JUNIT3 framework is used.

public void testRun() {}

Third, use

The API we use is mainly from four parts:

    • Robotium Frame Core class solo
    • ActivityInstrumentationTestCase2 class under the instrumentation framework
    • Assertion method Under Unit3
    • Getxx or Findxx methods for UI components

Here we are simply explaining the solo class API alone.

The Solo class is the core class in Robotium, and almost all of the test methods are implemented by invoking it.

1.getXX () matching method

GetView (int id) is generally used, GetText (String text) matches the component you want to manipulate, and if not, you can try Getbutton (), getImage (), etc.

The Getcurrentactivity () method returns the activity displayed by the interface.

2.action () Operation method
    • Clickonview (), Clickontext ()
    • Clearedittext (), Entertext ()
    • Clickinlist (), Clickinrecyclerview ()
    • Scrolldown (), Scrollviewtoside () (if it is a ListView, etc., it is not recommended here, it is better to use the method of MoveTo, etc.)
    • GoBack ()
3.ssert ()/search () Assertion method
    • Assert: Only solo. Assertcurrentactivity () method
    • Search () returns a Boolean value used for logical judgments, assertions.
    • Searchxxx (), waitxxx () in conjunction with the Assertequal () method.
4.waitXX (, Time) Wait method

Waitforactivity (), and so on, returns a Boolean value.

The condition is set in time, and the next step is performed immediately, not necessarily waiting for time.

At the same time we can use the Waitxx method of returning false as a stable timer, I often use waitforemptyactivitystack ().

Three functions: Wait for program response, logical judgment, slow test speed

Note: The extension of the Waitxx method: Waitforcondition () is used to support all judging conditions, as shown in the following example:

solo.waitForCondition(new myCondition(viewGroup), 3000)class myCondition implements Condition {    Object viewGroup;    myCondition(Object viewGroup) {        this.viewGroup = viewGroup;    }    @Override    public boolean isSatisfied() {        return viewGroup != null;    }}
Iv. Practice

Splashactivity.java (the main difficulty here is the selection of the traversal and judging conditions of the ListView or Recyclerview component)

Demand:

1. Enter from the Start page

2, switch cities, traverse all cities

3. Search 1-9

4. If the search results return multiple matching values, traverse all matching values.

5, if enter the site details, traverse all routes, click the Favorites button and cancel the collection

6, if enter the line details, traverse all sites, refresh, and then reversing, repeat for the forward operation.

1. Enter from the Start page

The test goes to the first interface, which is our bound interface.
Public Splashactivitytest () throws ClassNotFoundException {
Super (Splashactivity.class);
}
The class name here is not a matter of this class, but the constructor method calls the class you want to enter.

2, switch cities, traverse all cities

Since the city list is a ListView or Recyclerview, the data is unknown to us, the layout is mutable, we cannot use direct clickontext, or Clickonview into a city.
For a ListView or Recyclerview solution There are three kinds, specific use to see the specific situation:

A, through traversal, get all the city collections, and then call Clickontext.
Get all City Collections:

/** * 在CityChooseActivity界面内得到城市列表 * * @return 城市列表 */private String[] getCities() {    solo.clickOnView(solo.getView(R.id.cll_mod_main_tab_mine));    solo.clickOnView(solo.getView(R.id.cll_row_city));    if (solo.waitForActivity(CityChooseActivity.class, 3000)) {        solo.waitForEmptyActivityStack(3000);        StickyListHeadersListView stickyLv =(StickyListHeadersListView)     solo.getCurrentActivity().findViewById(R.id.cll_city_change_list);        List cities = new ArrayList();        for (int i = 3; i < stickyLv.getAdapter().getCount(); i++) {            City city = (City) stickyLv.getAdapter().getItem(i);            cities.add(city.getCityName());        }        solo.goBack();        return (String[]) cities.toArray(new String[cities.size()]);    } else {        solo.goBack();        return new String[]{"天津", "北京"};}

There are three characteristics of the Clickontext method:

1) Especially stable, generally can find the corresponding view, no matter how many layers of view is wrapped.

2) If text is not displayed or the item is initialized, the method causes the ListView to scroll until the view is found.

Of course you can set whether to scroll to find.

3) because the mechanism to find the view or there are more than two of the same text view, the default selection of the first, you can set the number of selected.

But here we use

solo.clickOnView(solo.getView(R.id.cll_search_section));

solo.clearEditText((EditText) solo.getView(R.id.frame_toolbar_search_query));

solo.enterText((EditText) solo.getView(R.id.frame_toolbar_search_query), city);

solo.clickInList(1);

Borrow the function of the program, and test this function.

However, the drawback of this method is that you must first go to the interface where the ListView is located, initialize the Listrview, and then get the city collection, otherwise it is just an empty set, and the second is that some components cannot traverse to get the city collection.

B, Clickinlist () or Clickinrecyclerview ()

Workaround 1 defects, but the disadvantage is:

1) method Internal limitations if the triggering event is not bound to item, and the second is on item's child view, the event may not be triggered.

2) The method parameter is the index of the visible child, which requires position to index conversion and component scrolling for different interfaces.

3) If an item has two listener events, such as a collection of site details, it cannot be triggered.

(Note: Parameters starting from 1)

I use this approach to traverse all routes in the multi-result traversal and line details, which are described in detail below.

C, through a given component, through findlastvisibleitemposition or findviewbyposition to find the target view, and then find the specific sub-view, using Clickonview (TargetView);
The ultimate approach (with the exception of Clickonscreen) can almost solve all requirements, but is particularly troublesome and unstable. The instability is that even if position refers to the item number starting at 0, it still requires that the item be visible when the method executes, or else it will be a bug.
I traverse all the sites in the details of the route, using this method, detailed use will be described below.

3, search 1-94, if the search results return multiple matching values, traverse all matching values.

Because the results returned by different search content are different, we need to deal with the results of the search, and consider the poor network environment, resulting in the absence of results returned.

  for (String content:contents) {performsearch (content);    LOG.D ("Testtab", "query" + content);    LOG.D ("Testtab", "Handling returned results");        if (solo.waitforactivity (Linedetailactivity.class)) {log.d ("Testtab", "Enter line details interface");        Linemodule.run ();        Solo.goback ();    Solo.goback ();        } else if (Solo.waitforactivity (Stationdetailactivity.class)) {log.d ("Testtab", "Enter station details interface");        Stationmodule.run ();        Solo.goback ();    Solo.goback ();        } else if (Solo.searchbutton ("Retry", True)) {LOG.D ("Testtab", "No results returned");        Solo.goback ();    Continue        } else if (Solo.searchtext ("No suitable lines and stations found", true)) {LOG.D ("Testtab", "no suitable lines and stations found");        Solo.goback ();    Continue        } else if (Solo.waitforfragmentbyid (R.id.cll_fragment_fuzzy)) {traversalresults ();    Solo.goback (); }}

This is mainly the application of judging conditions. Note here that there are two points, one is the Solo.waitforfragmentbyid () method, in the program if the viewflipper mechanism is the rendering of another viewgroup, the target fragment is still initialized. Then Solo.waitforfragmentbyid () will not work properly.
The second is the Searchxx method. This method can penetrate the package and find the target view. But two disadvantages:

    • Because the method internally iterates through all the view, it takes a long time to find a match.
    • In a widget, such as a ListView, this method automatically scrolls to find a match, but no longer scrolls back to its original location, and you need to manually roll back to the first row when you call methods such as Clickinline.

The Traversalresults () method is traversed through the second method of traversing the ListView.

/** * Traversal returns multiple search results */private void Traversalresults () {ListView LV = (ListView) Solo.getview (R.ID.CLL_LV, 1);    Solo.scrolllisttotop (LV);    int sum = Lv.getadapter (). GetCount ();    LOG.D ("Testtab", "with" + sum + "result");    int itemCount = Lv.getlastvisibleposition ()-lv.getfirstvisibleposition () + 1;    LOG.D ("Testtab", "Visible item has" + ItemCount);    int loops = Sum/itemcount;    int last = sum% ItemCount;            if (Sum < ItemCount + 1) {for (int p = 1; p < sum + 1; p++) {solo.clickinlist (P);            Tolineorstation ();        Solo.goback (); }} else {for (int i = 0; i < loops + 1; i++) {if (I < loops) {for (int m = 1 ; M < ItemCount;                    m++) {//Because Scrolldown () logic and traversal conditions are irrelevant, the itemCount-1 stops traversing solo.clickinlist (m);                    LOG.D ("Testtab", "Search result traversal" + M);                    Tolineorstation ();                Solo.goback ();      } solo.scrolldown ();      } else {for (int n = itemcount-last + 1; n < itemCount + 1; n++) {Solo.clic                    Kinlist (n);                    Tolineorstation ();                Solo.goback (); }            }        }    }}

Need to get the total number of three value item, single page visible item number, the remainder of the first two division, concrete logic see above code.

Note the logic in processing the last page.

The last place to note:

ListView lv = (ListView) solo.getView(R.id.cll_lv, 1);

Index is 1, which is because it can then match to two ListView and select the second one.

5, if enter the site details, traverse all routes, click the Favorites button and cancel the collection

Two steps, traversal click each item, traverse click each Favorites button

Traversal clicks on each item, gets the total item count, the number of item in the screen, the quotient and remainder of the first two division, each cycle loops through clickinline each item on the screen, loops the Shangga number of times, and the last time only needs to traverse the count of remaining item.

@Overridepublic void Run () {solo.waitforactivity (Stationdetailactivity.class);//Ensure that the Recyclerview is not empty.    Recyclerview Recyclerview = (recyclerview) solo.getview (r.id.cll_station_detail_list);    Find the target Recyclerview, which is more effective than getcurrentactivity (). Findviewbyid ().    Linearlayoutmanager Mlinearlayoutmanager = (Linearlayoutmanager) Recyclerview.getlayoutmanager ();    int sum = Recyclerview.getadapter (). GetItemCount ();    LOG.D ("Testtab", "total" + sum + "line"); int itemCount = ((Linearlayoutmanager) Recyclerview.getlayoutmanager ()). Findlastvisibleitemposition ()-(( Linearlayoutmanager) Recyclerview.getlayoutmanager ()). Findfirstvisibleitemposition () + 1;//calculates the number of item displayed on the screen int loops = Sum/itemcount; you need to scroll a few times int last = sum% ItemCount; final if (Sum < ItemCount + 1) {for (int p = 0; P < sum;            p++) {Clickitem (P);        Clickfavourinstation (Mlinearlayoutmanager, p); }} else {for (int i = 0; i < loops + 1; i++) {if (I < loops) {//Guaranteed not to hit the back button recyclerview.smoothscrolltoposition (ItemCount * i);//due to solo.scrolldown () instability                    Stable positioning for (int m = 0; m < itemCount; m++) {Clickitem (M);                Clickfavourinstation (Mlinearlayoutmanager, I * itemCount + m);            } solo.scrolldown (); } else {int lastpageitemscount = ((Linearlayoutmanager) Recyclerview.getlayoutmanager ()). Findlastvisibleit                Emposition ()-((Linearlayoutmanager) Recyclerview.getlayoutmanager ()). Findfirstvisibleitemposition () + 1; for (int n = lastpageitemscount-last, q = 0; n < lastPageItemsCount-1; n++, q++) {Clickitem (n)                    ;                Clickfavourinstation (Mlinearlayoutmanager, loops * itemCount + q); }            }        }    }}

Click the Favorites button and cancel the collection:

The main idea is to ensure that the item is visible, find the target item's view through Findviewbyposition, and then find the sub-view,click that handles the listener event.

private void clickFavourInStation(LinearLayoutManager mLinearLayoutManager, int i) {        Log.d("TestTab", "点击收藏");        ViewGroup targetGroup = (ViewGroup) mLinearLayoutManager.findViewByPosition(i);        LineStnView mLineStnView = (LineStnView) targetGroup.getChildAt(1);        if (mLineStnView.getX() < 0) {            mLineStnView = (LineStnView) targetGroup.getChildAt(0);        }        View v = mLineStnView.findViewById(R.id.fav_view);        solo.clickOnView(v);        if (solo.waitForDialogToOpen()) {            solo.clickOnText("取消收藏");        } else {            solo.clickOnView(v);            solo.waitForDialogToOpen(2000);            solo.clickOnText("取消收藏");        }    }
6, if enter the line details, traverse all sites, refresh, and then reversing, repeat for the forward operation.

The main idea is to get the list component through GetView, make the target item that we want to select remain in the screen by the method given by the component, then findviewbyposition find the component of the target item, click.

A flag value is set here to record whether it has been changed.

private void Traversalallstat (Boolean flag) {Solo.waitforemptyactivitystack (2000);    Realtimepanelcontent content = (realtimepanelcontent) solo.getview (r.id.cll_real_time_panel_content);    LOG.D ("Testtab", "obtaining instances of realtimepanelcontent");    Linearlayoutmanager Mlinearlayoutmanager = (Linearlayoutmanager) Content.getlayoutmanager ();    LOG.D ("Testtab", "obtaining instances of Linearlayoutmanager");    int sum = Content.getadapter (). GetItemCount ();//Gets the number of stations LOG.D ("Testtab", "Get to Station" + string.valueof (sum-1));    Content.movetoposition (3);    Solo.waitforemptyactivitystack (2000);    LOG.D ("Testtab", "Wait for 2s to tab move to left");    int lastposition = Mlinearlayoutmanager.findlastvisibleitemposition ();    LOG.D ("Testtab", "interface appears last item of position" + lastposition);        for (int i = 0; i < sum-1; i++) {final ViewGroup viewgroup;        LOG.D ("Testtab", "current position is" + string.valueof (i));            if (I < lastposition) {solo.waitforemptyactivitystack (1000); ViewGroup = (viewgroup) mlinearlayoutmanager.findviewbyposition (i); if (!solo.waitforcondition (new Mycondition (ViewGroup), 3000)) | | (!viewgroup.isshown ()))                {LOG.D ("Testtab", "ViewGroup is null");                Content.movetoposition (i);                LOG.D ("Testtab", "because ViewGroup is null, move" + i + "to the Middle");                i--;                LOG.D ("Testtab", "Keep position position unchanged");            Continue            } log.d ("Testtab", "ViewGroup not NULL");            View Viewtoclick = Viewgroup.findviewbyid (r.id.cll_apt_station_name); if ((!viewtoclick.isshown ()) | | (!solo.waitforview (Viewtoclick, (), true)))                {//Here repeatedly verifies whether the view is empty or not visible, or the event is not triggered}                LOG.D ("Testtab", "Viewtoclick not visible");                Content.movetoposition (i);                LOG.D ("Testtab", "Viewtoclick not visible, will" + i + "move to the Middle");                i--;                LOG.D ("Testtab", "Keep position position unchanged");            Continue } Solo.clickonview (Viewtoclick);            LOG.D ("Testtab", "click to position" + string.valueof (i));                if (!solo.waitfordialogtoclose (6000)) {LOG.D ("Testtab", "refresh box does not appear");                Content.movetoposition (i);                i--;                LOG.D ("Testtab", "Keep position position unchanged");            Continue            } log.d ("Testtab", "click to collect");            Clickfavourinline ();            LOG.D ("Testtab", "Click to refresh");        Clickrefresh ();            } else {content.movetoposition (lastposition);            LOG.D ("Testtab", "add" + lastposition + "move to Middle");            Solo.waitforemptyactivitystack (2000);            LOG.D ("Testtab", "Waiting for 2s");            Lastposition = Mlinearlayoutmanager.findlastvisibleitemposition ();            LOG.D ("Testtab", "Change lastposition to" + lastposition);            ViewGroup = (viewgroup) mlinearlayoutmanager.findviewbyposition (i); if (!solo.waitforcondition (new Mycondition (ViewGroup), 3000)) | | (!viewgroup.isshown ())) {LoG.D ("Testtab", "ViewGroup is null");                Content.movetoposition (i);                LOG.D ("Testtab", "move" + i + "to Middle");                i--;                LOG.D ("Testtab", "Keep position position unchanged");            Continue            } View Viewtoclick = Viewgroup.findviewbyid (r.id.cll_apt_station_name);                if (!viewtoclick.isshown ()) {LOG.D ("Testtab", "Viewtoclick not visible");                Content.movetoposition (i);                LOG.D ("Testtab", "Viewtoclick not visible, will" + i + "move to the Middle");                i--;                LOG.D ("Testtab", "Keep position position unchanged");            Continue            } solo.clickonview (Viewtoclick);            LOG.D ("Testtab", "click to position" + string.valueof (i));                if (!solo.waitfordialogtoopen (6000)) {LOG.D ("Testtab", "refresh box does not appear");                Content.movetoposition (i);                i--;                LOG.D ("Testtab", "Keep position position unchanged");            Continue } log.d ("TesTTab "," click to collect ");            Clickfavourinline ();            LOG.D ("Testtab", "Click to refresh");        Clickrefresh ();            } if (i = = sum-2 && flag) {flag = false;            LOG.D ("Testtab", "Toggle flag, no re-commutation");            Clickchangedec ();            LOG.D ("Testtab", "click Commutation");            LOG.D ("Testtab", "re-traversal");        TRAVERSALALLSTAT (flag);            } if (!solo.waitfordialogtoclose (60000)) {LOG.D ("Testtab", "Refresh failed");        Solo.goback (); }    }}
Wu, Caution

1, the most stable and most commonly used Solo.clickonview (Solo.getview (r.id.xxx)), can be encapsulated into a click on the ID, priority use.

2. Time Control

Too slow to meet our rapid testing needs

Too fast, will lead to two problems, one is the previous action is not finished (the action itself is time-consuming or bad network environment), the latter action triggers cannot find the component, the second is a parallel conflict, such as the ListView before a move required to slide the ListView, the latter requires a move upward.

Workaround: The Waitxx method waits for the action to complete if it is not completed within the specified time

3, the scope of the interface

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Robotium Automated Testing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.