Pyuiantomator implements Android automated testing

The tool Python packageexists in the form of a piptest machine (PC) by installing it.

1
pip install uiautomator

After installation, you don't need to install anything on the Android device, as long as the device is connected to the host through adb, you can operate the UI controls of the Android device through Python in the host.

Here is a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from uiautomator import device as d
 
# Turn on screen
d.screen.on()
 
# press back key
d.press.back()
 
# click (x, y) on screen
d.click(x, y)
 
# check unchecked checkbox
checkbox = d(className= 'android.widget.CheckBox' , checked= 'false' )
checkbox.click()
 
# click button with text 'Next'
d(text= "Clock" ).click()
button = d(className= 'android.widget.Button' , text= 'Next' )
button.click()
 
# swipe from (sx, sy) to (ex, ey)
d.swipe (sx, sy, ex, ey)

For more detailed usage, please refer to the project documentation .

In this way, we can greatly simplify the way Python operates UI controls, no longer need to UI Automator APIwrite test cases in Java, and no longer need to repeatedly compile jar files, saving the trouble of maintaining two sets of codes for the same test scenario , the whole process is also more Pythonic.

Of course, pyuiautomatorit is not perfect. After all, it is not officially maintained by Google. From my actual use experience, there are sometimes some problems. I will not expand it here, and I will write a separate blog later. However, in general, pyuiautomatorit is still very worthwhile to use, and it does greatly simplify the testing workload.

Now to continue the topic of this article, how do we use pyuiautomatorit for UI control operations?

In fact, as you can see from the above sample code, the operation of UI controls is divided into two steps, first is to locate the target control, and then to perform actions on the located control.

Positioning controls

In the UI, each control has many properties, such as class, text, , indexand so on. If we want to operate a certain control, we must first select the target control.

In the pyuiautomatorusage example above, the code for the control selection has been included:

1
2
checkbox = d(className= 'android.widget.CheckBox' , checked= 'false' )
button = d(className= 'android.widget.Button' , text= 'Next' )

In these two lines of code, the selection of checkbox and button is implemented respectively. The basic principle is that the target control can be uniquely determined through the specified control properties.

So, how do we know what properties the target control has, and what are the corresponding property values?

Google officially provides two tools, hierarchyviewerand uiautomatorviewer, these two tools are located in the <android-sdk>/tools/directory. The difference between these two tools and their respective characteristics will not be introduced in detail in this article. We only need to know that in terms of viewing control properties, these two tools have the same functions and the same interface. One is enough.

{: .center}
uiautomatorviewer

Through this tool, we can view the UI element information in the current device screen:

  • Detailed attribute information of UI elements displayed in the current Android device screen
  • Hierarchical structure of all UI elements on the current Android device screen

It should be emphasized that each time the tool executes a dump, the obtained UI information is limited to the content displayed in the foreground on the current screen.

After obtaining the information of UI elements, since UI controls are stored in a tree structure, and each control has an index attribute value, theoretically, any UI control can be uniquely specified through the hierarchical structure and index attribute.

However, this is not best practice. Because usually, the UI layout has many levels of tree structure, and it will cause extremely complicated writing when specifying through the hierarchical relationship, and it is difficult to see which control is specified from the code at a glance. Do not believe? Take a look at this example to understand. The following code corresponds to the control in the red box in the above figure. It can be seen that if each control is to be found from the top-level node, it is also a lot of work to find the path from the root node to the target control. , and it's very error-prone.

1
2
3
4
5
6
7
8
9
10
11
12
13
d(className='android.widget.FrameLayout')
.child(className='android.widget.LinearLayout')
.child(className='android.widget.FrameLayout')
.child(className='android.widget.FrameLayout')
.child(className='android.widget.FrameLayout')
.child(className='android.widget.FrameLayout')
.child(className='android.widget.FrameLayout')
.child(className='android.view.View')
.child(className='android.widget.FrameLayout')
.child(className='android.widget.FrameLayout')
.child(className='android.view.View')
.child(className='android.widget.FrameLayout')
.child(className='android.widget.TextView')

In practical applications, we mostly use the attribute information of the control to locate the control. In general, the texttarget control can be uniquely determined by using the attribute value. For example, to locate the red box in the above figure, the following code is enough.

1
d(text='UC headline has new news, click to refresh')

However, it often texthappens that the attribute value of the target control is empty. At this time, we generally use classthe combination of attributes and partial hierarchical relationships. It is also the red box in the above figure, we can also use the following methods to locate.

1
d(className='android.widget.FrameLayout').child(className='android.widget.TextView')

It can be seen that the same control can be positioned in multiple ways. For specific positioning methods, please refer to the following guidelines:

  • The positioning method should ensure accurate positioning
  • Positioning should be as simple as possible
  • The positioning method should be as stable as possible, even if the screen interface changes, the positioning method will not fail

The accuracy of the positioning method is mentioned here, so how to verify it? The trick is to just take .countand .infoattribute values.

1
2
3
4
>>> d(text= 'UC头条有新消息,点击刷新').count
1
>>> d(text= 'UC头条有新消息,点击刷新').info
{ u'contentDescription': None, u'checked': False, u'clickable': True, u'scrollable': False, u'text': u'UC\u5934\u6761\u6709\u65b0\u6d88\u606f\uff0c\u70b9\u51fb\u5237\u65b0', u'packageName': u'com.UCMobile.projectscn1098RHEAD', u'selected': False, u'enabled': True, u'bounds': { u'top': 1064, u'left': 42, u'right': 1038, u'bottom': 1136}, u'className': u'android.widget.TextView', u'focusable': False, u'focused': False, u'checkable': False, u'resourceName': None, u'longClickable': False, u'visibleBounds' : { u'top' : 1064 , u'left' : 42 , u'right' : 1038 , u'bottom' : 1136 }, u'childCount' : 0 }

When the .countattribute value is 1 and .infothe content of the attribute value is consistent with the attribute value of the target control, it can be determined that the positioning method we adopt is accurate.

Control operation

After locating a specific control, the operation is easier.

In pyuiautomator, UI Automatorthe UI operation actions are encapsulated, and the commonly used operation actions are:

  • .click()
  • .long_click()
  • .swipe
  • .drag

pyuiautomatorFor more operations, we can query the document to find the appropriate method according to the actual needs of our test scenario .

 

 

Reference documentation

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326607528&siteId=291194637