Monkeyrunner for Android automated testing solves the problem of duplicate IDs

From: http://www.51testing.com/html/81/22381-854342.html

 

Time flies so fast, it's been over a year since the last blog post in the monkeyrunner series. Over the past year, I have experienced too many changes, and I have not had time to summarize and share. It was not until today that I talked about monkeyrunner with my friends on Weibo, and I remembered to take this opportunity to summarize some of the experience and skills I have accumulated before. I will share it with you again here. Now when it comes to functional automation testing tools on the Android side, there are actually quite a few, such as Robotium, which has been popular for a long time, Uiautomator, a rising star, and appium across platforms. Almost from the tool level, it can still meet everyone's requirements. As one of them, MonkeyRunner is actually not a particularly easy-to-use one, and I don't use it much. Because after all, it is derived from SL4A, and it is not based on the direct blood relative Instrumentation of Android. It is inherently slow, error-prone, and has few available interfaces. It can be said to be a bit "inborn". Of course, there are still some advantages. For example, it is written based on Jython language, the syntax is simple and easy to learn, it can be used across applications, it can operate tests directly by ID, and it does not require signatures and other features that other tools do not have, so sometimes it has its use. After everyone learns and masters it, there should be some opportunities to use it, and it is not bad for emergency rescue or something. Since Monkeyrunner is inherently deficient, if you want to make it easy to use, of course, you can only make up for it the day after tomorrow. Some time ago, I found a very powerful monkeyrunner third-party library wrapEasyMonkey on the Internet. It is repackaged based on EasyMonkeyDevice, and adds automatic exception handling, failure retry, case management, assertion, and getting the text on the control, etc., greatly enhanced The original function of monkeyrunner makes monkeyrunner more powerful than one level. In addition to the fact that the operation is still relatively slow, it can be said that almost everything else has been greatly improved. To be honest, the native monkeyrunner is almost impossible to use directly. Therefore, it is recommended to use monkeyrunner as your own test tool for children's shoes, you can find this bag to use, it is really easy to use. The specific usage will not be verbose here. The author's tutorial is still very detailed. I believe that children's shoes with a certain python foundation should understand it. But here, I want to focus on sharing not only this third-party package, but also my personal thoughts on some improvements to this package. In the package provided by the author of wrapEasyMonkey, many methods operate according to the control ID, such as getView(self, id). But friends who often do Android automated testing must know that there is a problem here. In many cases, the controls in our app either have no ID, or the ID value is repeated. In this case, it is definitely impossible to get a reference to this control based on the ID. So what to do? I was also very troubled by this problem at the time, but then I carefully studied the control tree diagram obtained by Hierarchy Viewer. In fact, we can completely based on the position of the child node where each control is located, combined with the characteristics of the indeterminate parameters of the python function, go to It is much more convenient to obtain a reference to any child node of any parent node with a known ID, and then use this reference as a parameter to obtain its corresponding text, assertion, etc., and will no longer suffer from no ID or duplicate ID. restricted. Of course, to achieve such a function, some functions in the original package need to be modified. Here I give an actual example to illustrate it. Suppose we now test the contact app that comes with Android. Suppose we add a contact first. Now we use monkeyrunner to verify whether the information of the contact we added is correct. There are actually several more important operations involved here: 1. Get the corresponding control 2. Determine whether the above text is consistent with the expectation, that is, the part represented by the three red boxes in the figure below. The complete picture in the hierarchy viewer is relatively large and cannot be displayed here, so you can see it yourself through this hierarchy viewer. Judging from the tree structure displayed in the hierarchy viewer, the control ID of the phone number 158xxxxxxxx and the email address [email protected] are both text2, which is obviously repeated. So there is no way to use the getView(self, id) method in the original package to get the reference of this view. Is that impossible? In fact, we can look at it from another point of view, that is, not from the perspective of ID, but from the perspective of the nodes of this control tree to think about how to obtain the reference of the control. We can see that in the box corresponding to each control in the hierarchy viewer diagram, there is a number in the lower right corner, as shown by 0 and 1 in the red box in the following figure. In fact, this number is the index value of the control in the sibling node of the same level. After we know this index value, we can use the parentView. children[index] property to get the object reference of the child node corresponding to any parent node. The parentView can be any parent node with a valid ID in the tree diagram, and then use the variable parameter list feature of the python function to pass in the index list of the desired control to construct a string that gets any node reference, thus obtaining its citations. The core code is as follows: def getChildView(self, parentId, *childSeq): hierarchyViewer = self.device.getHierarchyViewer() str_getchildview="hierarchyViewer.findViewById('" + parentId +"')" for index in childSeq: str_getchildview+=('. children[' + str(index) + ']') exec 'child_view=' + str_getchildview return child_view Now let's see how this code works. For example, the screenshot of the hierarchy viewer of the contact number control in the contact details interface we just now takes is as follows: The object reference of the contact number control can be obtained by this statement: phone_number=device.getChildView('id/contact_data', 0, 0, 1 , 0). Where "contact_data" is the ID of its parent object, this ID must meet two conditions, namely valid and unique. Through this ID, we can get a reference to any of its descendants, 0,0,1, 0 is the position of the contact control on the index chain in the object tree, which should be easy to understand by comparing the diagram. With this reference, we can better modify all methods that take ID as a parameter, and you can change whichever one you want. Here I will give an example. For example, there is a method in the wrapEasyMonkey package that is used to get the text on the control, getTextById(self, id), which is also the method we must use when we want to verify the text. But as shown in the figure above, in fact, the ID of the contact's control is duplicated (it is the same as the ID of the email address control), we can't use this duplicate ID to call the getTextById method, so we can only write according to what I just wrote. The method to get the reference of the contact control first, and then change the method of getting the text to get the text according to the reference of the passed view. The core code is as follows: def getText(self,view): if view != None: return (view.namedProperties.get('mText').toString().split('=')[1]).encode('utf8 ') Now it will be much more flexible, even if you want to get the object without ID or the ID is repeated, it will not affect your operation, because its position in the object tree cannot be repeated, huh, huh. Well, that's all for this time. Here, I am just writing some words to attract others from my own thoughts and feelings. If there is something wrong, you are welcome to correct me. Of course, you are also welcome to put forward more ideas. Let’s improve our tools together and automate the Android platform. better, hehe. mText').toString().split('=')[1]).encode('utf8') This will be much more flexible, even if you want to get the object without ID or the ID is repeated, it will not affect Your operation cannot be repeated because of its position in the object tree, hehe. Well, that's all for this time. Here, I am just writing some words to attract others from my own thoughts and feelings. If there is something wrong, you are welcome to correct me. Of course, you are also welcome to put forward more ideas. Let’s improve our tools together and automate the Android platform. better, hehe. mText').toString().split('=')[1]).encode('utf8') This will be much more flexible, even if you want to get the object without ID or the ID is repeated, it will not affect Your operation cannot be repeated because of its position in the object tree, hehe. Well, that's all for this time. Here, I am just writing some words to attract others from my own thoughts and feelings. If there is something wrong, you are welcome to correct me. Of course, you are also welcome to put forward more ideas. Let’s improve our tools together and automate the Android platform. better, hehe.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326338742&siteId=291194637