Integrating UI Performance into your testing practices guarantees interaction with your applications satisfies users’ demands.
Showing posts with label uiautomator. Show all posts
Showing posts with label uiautomator. Show all posts
Wednesday, June 28, 2017
Analyzing Android UI Performance
Labels:
android,
AndroidViewClient,
performance,
uiautomator,
unit test
Friday, March 17, 2017
Detecting memory leaks on Android apps
More often than it should you find yourself wondering if your application is leaking memory and if so what, where and how.
A lot of questions that usually don't have enough answers.
There are many well know ways your application can leak memory. To name a few
If you are interested in more detailed descriptions of these common ways your app can leak memory this article will help you.
Also, as there are pitfalls there are tools to help you find them. Again, to name a few
To do an effective use of these tools and uncover memory leaks you should stress your app, running it for a while, or forcing continuous invocations of Activities, perhaps navigation back to the Home screen and launching the Activity again and again. While you can do this manually and the most obvious cases will be detected, it is always more efficient to automate these steps so they can be run before and after to verify that you actually solved the problem.
And what better than AndroidViewClient/culebra to automate these steps as we have discussed so many times in previous articles. Precisely, one of the latest additions is the ability to capture dumpsys information and create plots with it.
This is an example of a method we can define to exercise our Activities including some extra steps like stopping the application to start clean and forcing garbage collection along the way (see complete source code here)
With every iteration, we are collecting the dumpsys meminfo for the process, exiting the app by sending BACK and returning to Home, and at the end, we plot the chart.
We can easily see that while we are forcing GC the amount of memory used, the number of Activities and Views are constantly increasing.
As always, you can find more information about AndroidViewClient/culebra in its wiki at https://github.com/dtmilano/AndroidViewClient/wiki, about CulebraTester at http://culebra.dtmilano.com/ and https://github.com/dtmilano/CulebraTester-public/wiki and if you have any question you can ask in Stackoverflow using http://stackoverflow.com/questions/tagged/androidviewclient.
Hope this help you spot some leaks in your app.
A lot of questions that usually don't have enough answers.
There are many well know ways your application can leak memory. To name a few
- static references to Contexts, Views or Activities
- inner classes holding a reference to the outer class
- anonymous classes, commonly used in listeners
- drawables holding a reference to the Context
- and many more cases
If you are interested in more detailed descriptions of these common ways your app can leak memory this article will help you.
Also, as there are pitfalls there are tools to help you find them. Again, to name a few
- Android Studio monitors
- dalvik and art GC log messages
- heap dumps
- dumpsys
- etc.
To do an effective use of these tools and uncover memory leaks you should stress your app, running it for a while, or forcing continuous invocations of Activities, perhaps navigation back to the Home screen and launching the Activity again and again. While you can do this manually and the most obvious cases will be detected, it is always more efficient to automate these steps so they can be run before and after to verify that you actually solved the problem.
And what better than AndroidViewClient/culebra to automate these steps as we have discussed so many times in previous articles. Precisely, one of the latest additions is the ability to capture dumpsys information and create plots with it.
This is an example of a method we can define to exercise our Activities including some extra steps like stopping the application to start clean and forcing garbage collection along the way (see complete source code here)
def __plot_dumpsys_meminfo(self, pkg, activity, method=None): self.device.shell("am force-stop %s" % pkg) for n in range(20): if n % 5 == 0: self.device.shell( "run-as %s pgrep -L 10 %s" % (pkg, pkg)) self.device.startActivity("%s/%s" % (pkg, activity)) time.sleep(2) if method: method() self.plot.append(Dumpsys(self.device, Dumpsys.MEMINFO, pkg)) self.device.press('BACK') time.sleep(0.5) self.device.press('BACK') time.sleep(0.5) self.device.press('HOME') time.sleep(0.5) self.plot.plot()
With every iteration, we are collecting the dumpsys meminfo for the process, exiting the app by sending BACK and returning to Home, and at the end, we plot the chart.
We can easily see that while we are forcing GC the amount of memory used, the number of Activities and Views are constantly increasing.
As always, you can find more information about AndroidViewClient/culebra in its wiki at https://github.com/dtmilano/AndroidViewClient/wiki, about CulebraTester at http://culebra.dtmilano.com/ and https://github.com/dtmilano/CulebraTester-public/wiki and if you have any question you can ask in Stackoverflow using http://stackoverflow.com/questions/tagged/androidviewclient.
Hope this help you spot some leaks in your app.
Labels:
android,
AndroidViewClient,
culebra,
monkeyrunner,
python,
stackoverflow,
tests,
uiautomator
Saturday, May 14, 2016
CulebraTester Private Beta Opt-in
Android testing can be complicated, time-consuming, and tedious.
What if it didn’t have to be?
CulebraTester provides a real-time point and click test recording through a web browser. This browser is connected to the Android device under test. Not sure what we mean?
Visit culebra.dtmilano.com for details.
If you are interested in being part of the Private Beta please fill out this form.
What if it didn’t have to be?
CulebraTester provides a real-time point and click test recording through a web browser. This browser is connected to the Android device under test. Not sure what we mean?
Visit culebra.dtmilano.com for details.
If you are interested in being part of the Private Beta please fill out this form.
Tuesday, December 22, 2015
AndroidViewClient/culebra vs. MonkeyRunner
More than 2 years ago I took a crucial decision in AndroidViewClient/culebra development plan and that was to free it from `monkeyrunner`, Jython and Chimpchat.
AndroidViewClient/culebra was liberated and starting with version 4.0.0 it does not require any other runtime environment than python 2.x (read announcement). It can be installed and upgraded using the corresponding platform tools like easy_install or pip and can be easily integrated into IDEs like Eclipse PyDev or Pycharm. It also improves speed, solves chimpchat bugs, and even provides a GUI whre you can automatically create tests or scripts without writing a single line of code.
Nonetheless, from time to time, I receive some questions or reports about problems with scripts created with `culebra` that are attempted to run with `monkeyrunner` or some other combinations. I take the blame for it. I failed at communicating that AndroidViewClient/culebra is a complete replacement and should not be used together.
In order to improve the situation I gave a very detailed, easy to follow, step-by-step answer to
Error of Script with MonkeyRunner and AndroidViewClient (Touch) on Stackoverflow, showing how you can create a test case that automatically starts.and Activity (Duolingo) , checks if some Views are on the screen, touches them and finally take the screenshot. All from the GUI.
AndroidViewClient/culebra was liberated and starting with version 4.0.0 it does not require any other runtime environment than python 2.x (read announcement). It can be installed and upgraded using the corresponding platform tools like easy_install or pip and can be easily integrated into IDEs like Eclipse PyDev or Pycharm. It also improves speed, solves chimpchat bugs, and even provides a GUI whre you can automatically create tests or scripts without writing a single line of code.
Nonetheless, from time to time, I receive some questions or reports about problems with scripts created with `culebra` that are attempted to run with `monkeyrunner` or some other combinations. I take the blame for it. I failed at communicating that AndroidViewClient/culebra is a complete replacement and should not be used together.In order to improve the situation I gave a very detailed, easy to follow, step-by-step answer to
Error of Script with MonkeyRunner and AndroidViewClient (Touch) on Stackoverflow, showing how you can create a test case that automatically starts.and Activity (Duolingo) , checks if some Views are on the screen, touches them and finally take the screenshot. All from the GUI.
I hope you find this explanation useful.
Labels:
android,
AndroidViewClient,
chimpchat,
culebra,
eclipse,
gui,
jython,
monkeyrunner,
python,
screenshot,
stackoverflow,
tests,
uiautomator
Friday, May 29, 2015
Google Cloud Test Lab
Yesterday, at Google I/O 2015, Cloud Test Lab was announced. One of its promoted features is: "you can run all of your tests across all devices, all at the same time--giving you access to massively parallel testing, bringing you deep and scaled insight".
Wow, that's pretty much the same I described in my previous post,
Wow, that's pretty much the same I described in my previous post,
android: culebra multi-device capabilities, minus the devices of course. You have to provide them.
Wouldn't it be great if Cloud Test Lab allows you to create your personalized tests, in addition to the automatically generated ones, using something like culebra GUI, where you can just point and click?
Labels:
adb,
android,
AndroidViewClient,
culebra,
uiautomator
Tuesday, May 19, 2015
android: culebra multi-device capabilities
culebra and its GUI both include multi-device capabilities in auto-generated test cases and scripts.
The test case or script is created as usual, but when the --multi-device option is present in the command line, the statements generated will be slightly different, still you can easily recognize them. These statements will include support for several devices using python's list comprehension.
For example, a typical self.vc.dump(window=-1) will become
[vc.dump(window=-1) for vc in self.allVcs()]
The test case or script is created as usual, but when the --multi-device option is present in the command line, the statements generated will be slightly different, still you can easily recognize them. These statements will include support for several devices using python's list comprehension.
For example, a typical self.vc.dump(window=-1) will become
[vc.dump(window=-1) for vc in self.allVcs()]
that is, for all the ViewClient's dump the content of the default window. You may wonder where the list of all ViewClient's obtained by self.allVcs() comes from. CulebraTestCase class handles multiple devices in its setUp() method and it's there where the lists of all devices, serial numbers and ViewClient's are handled
self.devices.append(ConnectedDevice(serialno=serialno, device=device, vc=vc))
Everything is handled automatically, so there's nothing to worry about. If only one device is connected to adb or a single serial number is passed to the test case as an argument, then the test case behaves exactly as single-device. However, if more than one device is connected to adb and they are specified on the command line the multi-device capabilities kicks-in and the test is run on all devices at the same time.
The special command line keyword all can be used to mean all the connected devices.
This trivial test for Calculator generated using
shows multi-device capabilities.
This trivial test for Calculator generated using
$ culebra --gui --multi-device \
--unit-test-class \
--do-not-verify-screen-dump \
-o ~/tmp/multi.py
--unit-test-class \
--do-not-verify-screen-dump \
-o ~/tmp/multi.py
shows multi-device capabilities.
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2014 Diego Torres Milano
Created on 2015-05-19 by Culebra v10.5.1
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
try:
sys.path.insert(0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'compresseddump': True, 'startviewserver': True, 'forceviewserveruse': False, 'autodump': False, 'ignoreuiautomatorkilled': True}
cls.options = {'start-activity': None, 'device-art': None, 'use-jar': False, 'multi-device': True, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': False, 'dictionary-keys-from': 'id', 'scale': 1, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'log-actions': False, 'use-regexps': False, 'null-back-end': False, 'auto-regexps': None, 'do-not-verify-screen-dump': True, 'verbose-comments': False, 'gui': True, 'find-views-with-text': True, 'prepend-to-sys-path': True, 'drop-shadow': False, 'output': '/Users/diego/tmp/multi2.py', 'unit-test-method': None, 'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
[_vc.dump(window=-1) for _vc in self.allVcs()]
[_vc.findViewWithTextOrRaise(u'2').touch() for _vc in self.allVcs()]
[_vc.sleep(_s) for _vc in self.allVcs()]
[_vc.dump(window=-1) for _vc in self.allVcs()]
[_vc.findViewWithContentDescriptionOrRaise(u'''plus''').touch() for _vc in self.allVcs()]
[_vc.sleep(_s) for _vc in self.allVcs()]
[_vc.dump(window=-1) for _vc in self.allVcs()]
[_vc.findViewWithTextOrRaise(u'1').touch() for _vc in self.allVcs()]
[_vc.sleep(_s) for _vc in self.allVcs()]
[_vc.dump(window=-1) for _vc in self.allVcs()]
[_vc.findViewWithContentDescriptionOrRaise(u'''equals''').touch() for _vc in self.allVcs()]
[_vc.sleep(_s) for _vc in self.allVcs()]
[_vc.dump(window=-1) for _vc in self.allVcs()]
if __name__ == '__main__':
CulebraTests.main()
Then, when you run the test with several devices connected as
$ ~/tmp/multi.py -s all
you will obtain something like this
Labels:
adb,
android,
AndroidViewClient,
culebra,
monkeyrunner,
python,
tests,
uiautomator,
unit test
Wednesday, May 13, 2015
android: beautiful screenshots, take 2
In my previous post, android: obtaining beautiful screenshots automatically, I introduced an automated way of obtaining screenshots of your application perhaps after doing some actions that would take considerably time to do manually over time.
We described how culebra intuitive UI could help you create the automation script even if you don't know anything about programing or python.
However, for simpler cases or when you just want to take one screenshot and an automation script is not worth the effort, dump, another tool in AndroidViewClient's toolbox can be used.
Simply, to take a screenshot and add device art, shadow and glare:
or, with the long option which are easier to remember
Now taking advantage of this opportunity. I would like to introduce some new device art support added in the latest version, like this Samsung Galaxy S4 (this screenshot has been taken with the previous command)
We described how culebra intuitive UI could help you create the automation script even if you don't know anything about programing or python.
However, for simpler cases or when you just want to take one screenshot and an automation script is not worth the effort, dump, another tool in AndroidViewClient's toolbox can be used.
Simply, to take a screenshot and add device art, shadow and glare:
$ dump -f /path/to/image -ZBA auto
or, with the long option which are easier to remember
$ dump --save-screenshot=/path/to/file \
--drop-shadow \
--glare \
--device-art=auto
--drop-shadow \
--glare \
--device-art=auto
Now taking advantage of this opportunity. I would like to introduce some new device art support added in the latest version, like this Samsung Galaxy S4 (this screenshot has been taken with the previous command)
Labels:
adb,
android,
AndroidViewClient,
culebra,
dump,
python,
screenshot,
uiautomator
Friday, November 07, 2014
culebra: the magical drag
This time we are demonstrating how to include drag() method calls in the generated test script.
The little secret, and what adds some "magic" is that units of the generated method call can be selected between DIP (density-independent pixels, also known as dp) or PX (pixels). The former, allows to give the generated test some independence of the physical screen size it is running on by applying the inverse relationship between pixels and density. That is, when a point it's touched on the screen, the actual density it used to calculate the touched points in DIPs and used to provide the arguments for the drag() method.
This is the culebra auto-generated script after the interactions showed in the screencast are performed.
If you inspect the script you will notice that now the drag() method includes another argument, which is 0 in this case and indicates the orientation of the device, but we will be covering this in a future post.
And this is the screencast showing the emulator window (I used an emulator to easily capture the content but you can use any device), a terminal window where I run culebra and the culebra window where the interaction takes place.
The little secret, and what adds some "magic" is that units of the generated method call can be selected between DIP (density-independent pixels, also known as dp) or PX (pixels). The former, allows to give the generated test some independence of the physical screen size it is running on by applying the inverse relationship between pixels and density. That is, when a point it's touched on the screen, the actual density it used to calculate the touched points in DIPs and used to provide the arguments for the drag() method.
This is the culebra auto-generated script after the interactions showed in the screencast are performed.
If you inspect the script you will notice that now the drag() method includes another argument, which is 0 in this case and indicates the orientation of the device, but we will be covering this in a future post.
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2014 Diego Torres Milano
Created on 2014-11-07 by Culebra v8.14.3
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'startviewserver': True, 'forceviewserveruse': False, 'autodump': False, 'ignoreuiautomatorkilled': True}
cls.options = {'start-activity': None, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'dictionary-keys-from': 'id', 'scale': 0.5, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'do-not-verify-initial-screen-dump': True, 'use-regexps': False, 'auto-regexps': None, 'use-jar': False, 'verbose-comments': False, 'gui': True, 'find-views-with-text': True, 'output': '/home/user/tmp/grab-1.py', 'unit-test-method': None, 'append-to-sys-path': False, 'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
self.vc.dump(window=-1)
self.vc.device.dragDip((289.0, 485.0), (46.0, 484.0), 1000, 20, 0)
self.vc.sleep(1)
self.vc.dump(window=-1)
self.vc.device.dragDip((44.0, 468.0), (339.0, 473.0), 1000, 20, 0)
self.vc.sleep(1)
self.vc.dump(window=-1)
self.vc.device.dragDip((69.0, 478.0), (335.0, 485.0), 1000, 20, 0)
self.vc.sleep(1)
self.vc.dump(window=-1)
self.vc.device.dragDip((345.0, 491.0), (31.0, 485.0), 1000, 20, 0)
self.vc.sleep(1)
self.vc.dump(window=-1)
if __name__ == '__main__':
CulebraTests.main()
And this is the screencast showing the emulator window (I used an emulator to easily capture the content but you can use any device), a terminal window where I run culebra and the culebra window where the interaction takes place.
Labels:
adb,
android,
AndroidViewClient,
culebra,
emulator,
gui,
monkeyrunner,
python,
tests,
uiautomator,
unit test
Wednesday, November 05, 2014
culebra: cross-device application tests
In the previous post, we demonstrated how a real python unit test can be generated using the new culebra GUI to test any application or set of applications in any Android device by just interacting with the representation of the device screen, that looks pretty much as the emulator.
We also mentioned that the generated script does not store screen coordinates to interact with the Views but its logical attributes like content description, text or ids.
Well, now we will be demonstrating how the generated test that launches Calculator, enter some operation and verifies the actual result can be run unaffected on a completely different device. Remember that we used a Nexus 4 emulator to interact and generate the test and now we will be using a Nexus 7 tablet to run it.
Without further ado, here is the recorded screen of this Nexus 7 tablet running the test.
We also mentioned that the generated script does not store screen coordinates to interact with the Views but its logical attributes like content description, text or ids.
Well, now we will be demonstrating how the generated test that launches Calculator, enter some operation and verifies the actual result can be run unaffected on a completely different device. Remember that we used a Nexus 4 emulator to interact and generate the test and now we will be using a Nexus 7 tablet to run it.
Without further ado, here is the recorded screen of this Nexus 7 tablet running the test.
Labels:
adb,
android,
AndroidViewClient,
culebra,
emulator,
gui,
monkeyrunner,
nexus,
python,
tests,
uiautomator,
unit test
Monday, November 03, 2014
culebra: GUI to automatically generate Android application tests
We have mentioned AndroidViewClient/culebra in many recent post and we reviewed many of the most useful features, however what I'm introducing today is certainly a breakthrough in automatic generation of Android application tests.
The following tests was automatically generated by running culebra and interacting with the window that mimics the content of the device or emulator.
To really appreciate how this test has been automatically generated I uploaded a simple (and crude) video of the steps. In the screencast you can see the emulator window (I used an emulator to easily capture the content but you can use any device), a terminal window where I run culebra and the culebra window where the interaction takes place.
Enjoy the video.
One really (or I should say extremely) cool feature of theses tests is that you can run exactly the same tests on a completely different device, let's say a tablet, and the tests would run exactly the same because culebra is not storing screen coordinates to interact with the Views but its logical attributes, like content description, text or ids. That way the test is device agnostic.
I'm explaining it step-by-step in the next post.
The following tests was automatically generated by running culebra and interacting with the window that mimics the content of the device or emulator.
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2014 Diego Torres Milano
Created on 2014-11-02 by Culebra v8.11.1
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'startviewserver': True, 'forceviewserveruse': False, 'autodump': False, 'ignoreuiautomatorkilled': True}
cls.options = {'find-views-by-id': True, 'verbose-comments': False, 'find-views-with-content-description': True, 'save-view-screenshots': None, 'do-not-verify-initial-screen-dump': True, 'use-regexps': False, 'start-activity': None, 'find-views-with-text': True, 'unit-test-class': True, 'window': -1, 'save-screenshot': None, 'use-dictionary': False, 'scale': 0.5, 'use-jar': False, 'output': '/home/brldmila/tmp/calc-1.py', 'auto-regexps': None, 'interactive': False, 'append-to-sys-path': False, 'gui': True, 'dictionary-keys-from': 'id', 'unit-test-method': None}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
self.vc.dump(window=-1)
self.vc.device.press("HOME")
self.vc.dump(window=-1)
self.vc.findViewWithContentDescriptionOrRaise(u'''Apps''').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.vc.findViewWithTextOrRaise(u'Calculator').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.vc.findViewWithContentDescriptionOrRaise(u'''clear''').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.vc.findViewWithTextOrRaise(u'2').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.vc.findViewWithContentDescriptionOrRaise(u'''plus''').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.vc.findViewWithTextOrRaise(u'1').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.vc.findViewWithContentDescriptionOrRaise(u'''equals''').touch()
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
self.assertEquals(self.vc.findViewWithContentDescriptionOrRaise(u'''3''').getText(), u'''3''')
self.vc.device.touchDip(168.262910798, 932.957746479)
self.vc.sleep(CulebraTests.sleep)
self.vc.dump(window=-1)
if __name__ == '__main__':
CulebraTests.main()
To really appreciate how this test has been automatically generated I uploaded a simple (and crude) video of the steps. In the screencast you can see the emulator window (I used an emulator to easily capture the content but you can use any device), a terminal window where I run culebra and the culebra window where the interaction takes place.
Enjoy the video.
One really (or I should say extremely) cool feature of theses tests is that you can run exactly the same tests on a completely different device, let's say a tablet, and the tests would run exactly the same because culebra is not storing screen coordinates to interact with the Views but its logical attributes, like content description, text or ids. That way the test is device agnostic.
I'm explaining it step-by-step in the next post.
Labels:
adb,
android,
AndroidViewClient,
culebra,
emulator,
gui,
monkeyrunner,
python,
tests,
uiautomator,
unit test
Tuesday, March 18, 2014
culebra's less known features: auto-regexp
This post starts a new series illustrating AndroidViewClient/culebra's less know features. The first instalment is dedicated to an extremely useful feature: auto-regexp.
But before going deeper into this option let's analyze a bit the general use case.
Very often, in the process of writing functional test cases you find yourself having to verify the result of some previous actions on the UI by recognizing some aspects of the device screen.
Traditionally this is done obtaining the screenshot and then applying some computational method to identify elements in the image and being able to determine if it is exactly what we were waiting for or in some cases up to what degree, allowing some parts of the image to vary.
This subject has been treated here before, for example in monkeyrunner: visual image comparison. However, we will be aiming a much simpler method in this post. Instead of using the image representing the screen we will be using the logical representation of it, that is the tree of Views visible at any given time.
Let's also consider the our device or emulator is showing the lock screen and that is the condition we want to detect.
culebra helps us creating the script to achieve this.
$ culebra --find-views-with-text=on --output=lockscreen.py
then we can verify that the device or emulator is showing the lock screen simply by running the script
$ ./lockscreen.py
Nevertheless, when we run the script later, it will miserably fail with a message similar to this one
I'm sure you have already guessed the reason. When we generated the script, the text in the View was used to generate the line
com_android_keyguard___id_clock_view = vc.findViewWithTextOrRaise(u'5:47')
We need a regular expression. We could add it manually but culebra can also help us generating this scripts by identifying some constructions and replacing them by their regular expressions counterpart. The option, as we mentioned before is auto-regexp. This option also has a help sub-option to clarify the possible values
$ culebra --auto-regexp=help
Adding this option to the original command line we will have
$ culebra --find-views-with-text=on \
--auto-regexp=all \
--output=lockscreen.py
and as a result our generated script contains lines like
com_android_keyguard___id_clock_view = vc.findViewWithTextOrRaise(re.compile(u'[012]?\d:[0-5]\d'))
and the screen identification will succeed even if date and time change.
Hope this helps you with your culebra scripts.
But before going deeper into this option let's analyze a bit the general use case.
Very often, in the process of writing functional test cases you find yourself having to verify the result of some previous actions on the UI by recognizing some aspects of the device screen.
Traditionally this is done obtaining the screenshot and then applying some computational method to identify elements in the image and being able to determine if it is exactly what we were waiting for or in some cases up to what degree, allowing some parts of the image to vary.
This subject has been treated here before, for example in monkeyrunner: visual image comparison. However, we will be aiming a much simpler method in this post. Instead of using the image representing the screen we will be using the logical representation of it, that is the tree of Views visible at any given time.
Let's also consider the our device or emulator is showing the lock screen and that is the condition we want to detect.
culebra helps us creating the script to achieve this.
$ culebra --find-views-with-text=on --output=lockscreen.py
then we can verify that the device or emulator is showing the lock screen simply by running the script
$ ./lockscreen.py
Nevertheless, when we run the script later, it will miserably fail with a message similar to this one
Traceback (most recent call last):
File "./lockscreen-0.py", line 44, in
com_android_keyguard___id_clock_view = vc.findViewWithTextOrRaise(u'5:47')
File "/usr/local/lib/python2.7/dist-packages/androidviewclient-5.4.2-py2.7.egg/com/dtmilano/android/viewclient.py", line 2220, in findViewWithTextOrRaise
raise ViewNotFoundException("text", text, root)
com.dtmilano.android.viewclient.ViewNotFoundException: Couldn't find View with text='5:47' in tree with root=ROOT
I'm sure you have already guessed the reason. When we generated the script, the text in the View was used to generate the line
com_android_keyguard___id_clock_view = vc.findViewWithTextOrRaise(u'5:47')
We need a regular expression. We could add it manually but culebra can also help us generating this scripts by identifying some constructions and replacing them by their regular expressions counterpart. The option, as we mentioned before is auto-regexp. This option also has a help sub-option to clarify the possible values
$ culebra --auto-regexp=help
Available auto-regexps options:
help: prints this help
all: includes all the available regexps
date: (Mon|Tue|Wed|Thu|Fri|Sat|Sun), (January|February|March|April|May|June|July|August|September|October|November|December) [0123]\d
battery: Charging, \d\d%
clock: [012]?\d:[0-5]\d
$ culebra --find-views-with-text=on \
--auto-regexp=all \
--output=lockscreen.py
and as a result our generated script contains lines like
com_android_keyguard___id_clock_view = vc.findViewWithTextOrRaise(re.compile(u'[012]?\d:[0-5]\d'))
and the screen identification will succeed even if date and time change.
Hope this helps you with your culebra scripts.
Labels:
adb,
android,
AndroidViewClient,
culebra,
gui,
monkeyrunner,
python,
uiautomator
Thursday, October 10, 2013
AndroidViewClient/culebra version 4.6.0: now 100% pure python
AndroidViewClient/culebra v4.6.0 has been released bringing major improvements closing the gap with the existing APIs. This is demonstrated by the example scripts migrated to use AdbClient now, instead of MonkeyDevice.
monkeyrunner seems much farther in the rearview mirror.
monkeyrunner seems much farther in the rearview mirror.
changelog
- AdbClient: Added
isLocked()method to check if screen is locked - Fixed #55: drag doesn't work for old Android versions
- Removed
sys.pathmanipulation not needed for python - Read
ANDROID_ADB_SERVER_PORTenvironment variable to set adb PORT. This variable is set by Jenkins Android Emulator plugin. - Merge pull request #56 from knorrium/clean-whitespaces
- Check for sys.executable that may be not available on Windows
- Examples modified to use python
- Marked jar file creation as deprecated
- Improved UTF-8 treatment in messages
AdbClient.startActivity()raises exception on errors- Warns if modules are imported using 'monkeyrunner'
- Added image comparison
- Decode used only on python's 8-bit strings
- Restored
obtainAdbPath()used for android API <= 16 - Trap exception generated by integer division by zero in
takeSnapshot() - Fixed famebuffer exception
Labels:
adb,
android,
AndroidViewClient,
continuous integration,
culebra,
github,
monkeyrunner,
python,
uiautomator
Monday, September 09, 2013
AndroidViewClient/culebra takeSnapshot() improvements
The latest release of AndroidViewClient/culebra v.4.2.1 includes now the implementation of AdbClient.takeSnapshot(), replacing MonkeyDevice.takeSnapshot() used in previous releases.
Starting from AndroidViewClient v4.0.0, monkeyrunner was ditched in favor of plain good old python. This change brought massive speed improvements in running tests as it was described in AndroidViewClient/culebra version 4.0.0: now 100% pure python, and takeSnapshot() is not an exception.
In order to measure the improvement, 2 scripts were added to the examples, one taking a screenshot using MonkeyDevice.takeSnapshot() and the orher using the alternative AdbClient.takeSnapshot(). As with other functionality, the API is maintained so changes to existing scripts are unnecessary or just minimum.
As you may have been anticipating, the python script run much faster and this is illustrated in the following chart.
Something to take into account is that both script are almost the same, except for some improvements that are supported only by AndroidViewClient, like the possibility of requesting a verbose connection or specifying the device serial number in the command line.
Also, notice that instead of writeToFile() like MonkeyImage does, save() is used. This is because AdbClient.takeSnapshot() returns a real PIL Image and not a wrapper.
Hope you enjoyed the changes.
If you have any question or comments just post it on Google+ or Stackoverflow.
Starting from AndroidViewClient v4.0.0, monkeyrunner was ditched in favor of plain good old python. This change brought massive speed improvements in running tests as it was described in AndroidViewClient/culebra version 4.0.0: now 100% pure python, and takeSnapshot() is not an exception.
In order to measure the improvement, 2 scripts were added to the examples, one taking a screenshot using MonkeyDevice.takeSnapshot() and the orher using the alternative AdbClient.takeSnapshot(). As with other functionality, the API is maintained so changes to existing scripts are unnecessary or just minimum.
screenshot-monkeyrunner.py
The script taking the screenshot of the device or emulator using monkeyrunner.
#! /usr/bin/env monkeyrunner
'''
Copyright (C) 2012 Diego Torres Milano
Created on Set 5, 2013
@author: diego
'''
import sys
import os
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
if len(sys.argv) < 2:
print >> sys.stderr, "usage: %s filename.png" % sys.argv[0]
sys.exit(1)
filename = sys.argv.pop(1)
device = MonkeyRunner.waitForConnection()
device.takeSnapshot().writeToFile(filename, 'PNG')
screenshot.py
The script taking the screenshot of the device or emulator using python.
#! /usr/bin/env python
'''
Copyright (C) 2012 Diego Torres Milano
Created on Aug 31, 2013
@author: diego
'''
import sys
import os
from com.dtmilano.android.viewclient import ViewClient
if len(sys.argv) < 2:
sys.exit("usage: %s filename.png [serialno]" % sys.argv[0])
filename = sys.argv.pop(1)
device, serialno = ViewClient.connectToDeviceOrExit(verbose=False)
device.takeSnapshot().save(filename, 'PNG')
results
Both scripts were run to take the screenshot of a Nexus 4 (android api-18) home screen.As you may have been anticipating, the python script run much faster and this is illustrated in the following chart.
Something to take into account is that both script are almost the same, except for some improvements that are supported only by AndroidViewClient, like the possibility of requesting a verbose connection or specifying the device serial number in the command line.
Also, notice that instead of writeToFile() like MonkeyImage does, save() is used. This is because AdbClient.takeSnapshot() returns a real PIL Image and not a wrapper.
Hope you enjoyed the changes.
If you have any question or comments just post it on Google+ or Stackoverflow.
Labels:
adb,
android,
AndroidViewClient,
chimpchat,
culebra,
dump.py,
monkeyrunner,
python,
uiautomator
Tuesday, August 27, 2013
AndroidViewClient/culebra version 4.0.0: now 100% pure python
AndroidViewClient/culebra v4.0.0 has been released bringing major improvements and an incredible speed gain by removing the dependency on monkeyrunner and now using python as the interpreter.
I have been thinking about this change for a very long time but never had the time to do it. In one way or another I found workaround after workaround for monkeyrunner and ChimpChat problems. If monkeyrunner was not detecting that the device was not actually connected, AndroidViewClient was forcing a wake() after waitForConnection() returns to verify that everything was right or catching the Exception and showing a more meaningful message (code). If the connection attempt didn't time out and hangs AndroidViewClient was also providing a workaround (code).
Lately, on some Android devices, uiautomator is killed before finishing and the Killed message is also included in the output, and then AndroidViewClient also provided a workaround (code).
I could name several more, but I think you got the idea.
However, it wasn't until the introduction of this bug:
when things were really screaming for a long term solution and not just another workaround.
Then, I took adbclient module I have been developing some time ago to be able to run some stability tests (did I mention ChimpChat was not stable enough to run them?), modify it a bit and now AndroidViewClient/culebra and dump are not dependant on monkeyrunner or ChimpChat and can use any compatible python interpreter.
The inclusion of adbclient also brought some tremendous speed improvement, something you would thank if you have to run hundreds or thousands of tests.
These charts demonstrates the improvements:
This is just the beginning. Stay tuned and you will see more improvements coming.
I have been thinking about this change for a very long time but never had the time to do it. In one way or another I found workaround after workaround for monkeyrunner and ChimpChat problems. If monkeyrunner was not detecting that the device was not actually connected, AndroidViewClient was forcing a wake() after waitForConnection() returns to verify that everything was right or catching the Exception and showing a more meaningful message (code). If the connection attempt didn't time out and hangs AndroidViewClient was also providing a workaround (code).
Lately, on some Android devices, uiautomator is killed before finishing and the Killed message is also included in the output, and then AndroidViewClient also provided a workaround (code).
I could name several more, but I think you got the idea.
However, it wasn't until the introduction of this bug:
| Issue 58912: | UiAutomator and UiAutomation-based tests fail to run when chimpchat connection is present on 4.3 |
when things were really screaming for a long term solution and not just another workaround.
Then, I took adbclient module I have been developing some time ago to be able to run some stability tests (did I mention ChimpChat was not stable enough to run them?), modify it a bit and now AndroidViewClient/culebra and dump are not dependant on monkeyrunner or ChimpChat and can use any compatible python interpreter.
The inclusion of adbclient also brought some tremendous speed improvement, something you would thank if you have to run hundreds or thousands of tests.
These charts demonstrates the improvements:
Labels:
adb,
android,
AndroidViewClient,
chimpchat,
culebra,
dump.py,
github,
monkeyrunner,
python,
tests,
uiautomator
Wednesday, July 31, 2013
Android 4.3 (Jellybean) update breaks some things
It is quite annoying.
I guess this should not happen for a major release.
UiAutomator is kind of broken. I've found this problem on a Nexus 4 and also on emulator, so it seems generic. Now when Chimpchat opens a connection (i.e. monkeyrunner) and you try to run uiautomator from a different adb shell you'll get
07-30 23:49:51.821: D/AndroidRuntime(2951): >>>>>> AndroidRuntime START com.android.internal.os.RuntimeInit <<<<<<
07-30 23:49:51.821: D/AndroidRuntime(2951): CheckJNI is OFF
07-30 23:49:51.831: D/dalvikvm(2951): Trying to load lib libjavacore.so 0x0
07-30 23:49:51.841: D/dalvikvm(2951): Added shared lib libjavacore.so 0x0
07-30 23:49:51.841: D/dalvikvm(2951): Trying to load lib libnativehelper.so 0x0
07-30 23:49:51.841: D/dalvikvm(2951): Added shared lib libnativehelper.so 0x0
07-30 23:49:51.981: D/AndroidRuntime(2951): Calling main entry com.android.commands.uiautomator.Launcher
07-30 23:49:51.991: D/AndroidRuntime(2951): Shutting down VM
07-30 23:49:51.991: W/dalvikvm(2951): threadid=1: thread exiting with uncaught exception (group=0x415b9700)
07-30 23:49:51.991: D/dalvikvm(2951): Note: class Landroid/app/ActivityManagerNative; has 163 unimplemented (abstract) methods
07-30 23:49:51.991: E/JavaBinder(2951): Unknown binder error code. 0xfffffff7
07-30 23:49:51.991: E/ServiceManager(2951): error in getService
07-30 23:49:51.991: E/ServiceManager(2951): android.os.RemoteException: Unknown binder error code. 0xfffffff7
07-30 23:49:51.991: E/ServiceManager(2951): at android.os.BinderProxy.transact(Native Method)
07-30 23:49:51.991: E/ServiceManager(2951): at android.os.ServiceManagerProxy.getService(ServiceManagerNative.java:123)
07-30 23:49:51.991: E/ServiceManager(2951): at android.os.ServiceManager.getService(ServiceManager.java:55)
07-30 23:49:51.991: E/ServiceManager(2951): at android.app.ActivityManagerNative$1.create(ActivityManagerNative.java:1893)
07-30 23:49:51.991: E/ServiceManager(2951): at android.app.ActivityManagerNative$1.create(ActivityManagerNative.java:1891)
07-30 23:49:51.991: E/ServiceManager(2951): at android.util.Singleton.get(Singleton.java:34)
07-30 23:49:51.991: E/ServiceManager(2951): at android.app.ActivityManagerNative.getDefault(ActivityManagerNative.java:73)
07-30 23:49:51.991: E/ServiceManager(2951): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:76)
07-30 23:49:51.991: E/ServiceManager(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
07-30 23:49:51.991: E/ServiceManager(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
07-30 23:49:51.991: E/ServiceManager(2951): at dalvik.system.NativeStart.main(Native Method)
07-30 23:49:51.991: I/Process(2951): Sending signal. PID: 2951 SIG: 9
07-30 23:49:51.991: E/AndroidRuntime(2951): *** FATAL EXCEPTION IN SYSTEM PROCESS: main
07-30 23:49:51.991: E/AndroidRuntime(2951): java.lang.IllegalStateException: UiAutomationService android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy@427adc60already registered!
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.os.Parcel.readException(Parcel.java:1439)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.os.Parcel.readException(Parcel.java:1385)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.view.accessibility.IAccessibilityManager$Stub$Proxy.registerUiTestAutomationService(IAccessibilityManager.java:342)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.app.UiAutomationConnection.registerUiTestAutomationServiceLocked(UiAutomationConnection.java:173)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.app.UiAutomationConnection.connect(UiAutomationConnection.java:72)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.app.UiAutomation.connect(UiAutomation.java:188)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.uiautomator.core.UiAutomationShellWrapper.connect(UiAutomationShellWrapper.java:32)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.commands.uiautomator.DumpCommand.run(DumpCommand.java:74)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.commands.uiautomator.Launcher.main(Launcher.java:83)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235)
07-30 23:49:51.991: E/AndroidRuntime(2951): at dalvik.system.NativeStart.main(Native Method)
07-30 23:49:51.991: E/AndroidRuntime(2951): Error reporting crash
07-30 23:49:51.991: E/AndroidRuntime(2951): java.lang.NullPointerException
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:76)
07-30 23:49:51.991: E/AndroidRuntime(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
07-30 23:49:51.991: E/AndroidRuntime(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
07-30 23:49:51.991: E/AndroidRuntime(2951): at dalvik.system.NativeStart.main(Native Method)
UPDATE: 2013-AUG-27:
AndroidViewClient/culebra version 4.0.0: now 100% pure python describes a solution for this problem
I guess this should not happen for a major release.
UiAutomator is kind of broken. I've found this problem on a Nexus 4 and also on emulator, so it seems generic. Now when Chimpchat opens a connection (i.e. monkeyrunner) and you try to run uiautomator from a different adb shell you'll get
07-30 23:49:51.821: D/AndroidRuntime(2951): >>>>>> AndroidRuntime START com.android.internal.os.RuntimeInit <<<<<<
07-30 23:49:51.821: D/AndroidRuntime(2951): CheckJNI is OFF
07-30 23:49:51.831: D/dalvikvm(2951): Trying to load lib libjavacore.so 0x0
07-30 23:49:51.841: D/dalvikvm(2951): Added shared lib libjavacore.so 0x0
07-30 23:49:51.841: D/dalvikvm(2951): Trying to load lib libnativehelper.so 0x0
07-30 23:49:51.841: D/dalvikvm(2951): Added shared lib libnativehelper.so 0x0
07-30 23:49:51.981: D/AndroidRuntime(2951): Calling main entry com.android.commands.uiautomator.Launcher
07-30 23:49:51.991: D/AndroidRuntime(2951): Shutting down VM
07-30 23:49:51.991: W/dalvikvm(2951): threadid=1: thread exiting with uncaught exception (group=0x415b9700)
07-30 23:49:51.991: D/dalvikvm(2951): Note: class Landroid/app/ActivityManagerNative; has 163 unimplemented (abstract) methods
07-30 23:49:51.991: E/JavaBinder(2951): Unknown binder error code. 0xfffffff7
07-30 23:49:51.991: E/ServiceManager(2951): error in getService
07-30 23:49:51.991: E/ServiceManager(2951): android.os.RemoteException: Unknown binder error code. 0xfffffff7
07-30 23:49:51.991: E/ServiceManager(2951): at android.os.BinderProxy.transact(Native Method)
07-30 23:49:51.991: E/ServiceManager(2951): at android.os.ServiceManagerProxy.getService(ServiceManagerNative.java:123)
07-30 23:49:51.991: E/ServiceManager(2951): at android.os.ServiceManager.getService(ServiceManager.java:55)
07-30 23:49:51.991: E/ServiceManager(2951): at android.app.ActivityManagerNative$1.create(ActivityManagerNative.java:1893)
07-30 23:49:51.991: E/ServiceManager(2951): at android.app.ActivityManagerNative$1.create(ActivityManagerNative.java:1891)
07-30 23:49:51.991: E/ServiceManager(2951): at android.util.Singleton.get(Singleton.java:34)
07-30 23:49:51.991: E/ServiceManager(2951): at android.app.ActivityManagerNative.getDefault(ActivityManagerNative.java:73)
07-30 23:49:51.991: E/ServiceManager(2951): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:76)
07-30 23:49:51.991: E/ServiceManager(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
07-30 23:49:51.991: E/ServiceManager(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
07-30 23:49:51.991: E/ServiceManager(2951): at dalvik.system.NativeStart.main(Native Method)
07-30 23:49:51.991: I/Process(2951): Sending signal. PID: 2951 SIG: 9
07-30 23:49:51.991: E/AndroidRuntime(2951): *** FATAL EXCEPTION IN SYSTEM PROCESS: main
07-30 23:49:51.991: E/AndroidRuntime(2951): java.lang.IllegalStateException: UiAutomationService android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy@427adc60already registered!
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.os.Parcel.readException(Parcel.java:1439)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.os.Parcel.readException(Parcel.java:1385)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.view.accessibility.IAccessibilityManager$Stub$Proxy.registerUiTestAutomationService(IAccessibilityManager.java:342)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.app.UiAutomationConnection.registerUiTestAutomationServiceLocked(UiAutomationConnection.java:173)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.app.UiAutomationConnection.connect(UiAutomationConnection.java:72)
07-30 23:49:51.991: E/AndroidRuntime(2951): at android.app.UiAutomation.connect(UiAutomation.java:188)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.uiautomator.core.UiAutomationShellWrapper.connect(UiAutomationShellWrapper.java:32)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.commands.uiautomator.DumpCommand.run(DumpCommand.java:74)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.commands.uiautomator.Launcher.main(Launcher.java:83)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235)
07-30 23:49:51.991: E/AndroidRuntime(2951): at dalvik.system.NativeStart.main(Native Method)
07-30 23:49:51.991: E/AndroidRuntime(2951): Error reporting crash
07-30 23:49:51.991: E/AndroidRuntime(2951): java.lang.NullPointerException
07-30 23:49:51.991: E/AndroidRuntime(2951): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:76)
07-30 23:49:51.991: E/AndroidRuntime(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
07-30 23:49:51.991: E/AndroidRuntime(2951): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
07-30 23:49:51.991: E/AndroidRuntime(2951): at dalvik.system.NativeStart.main(Native Method)
This was perfectly valid and correct on Android 4.2.x. It still requires some investigation, but I wanted to post it here just in case you find the same, at least you won't feel alone.
UPDATE: 2013-AUG-27:
AndroidViewClient/culebra version 4.0.0: now 100% pure python describes a solution for this problem
Labels:
adb,
android,
AndroidViewClient,
chimpchat,
culebra,
dump.py,
monkeyrunner,
uiautomator
Tuesday, July 09, 2013
AndroidViewClient/culebra version 2.3.25 released
Github recently introduced some new features to its release system. There are several improvements. Though it was possible to tag versions before, and AndroidViewClient/culebra has been doing it for a while, now the release system is a first class citizen and can include binary files (solving one problem that was solved using Google Drive in previous releases).
Latest AndroidViewClient/culebra release (v2.3.25) can now be found at https://github.com/dtmilano/AndroidViewClient/releases/v2.3.25
These are the release notes:
The binary distribution and documentation can also be downloaded from the release.
More on these later.
Latest AndroidViewClient/culebra release (v2.3.25) can now be found at https://github.com/dtmilano/AndroidViewClient/releases/v2.3.25
These are the release notes:
Added methods to calculate dump distances
- Version 2.3.25
- Added Hamming distance
- Added Levenshtein distance
- Added View.__microStr__()
- Traverse refactoring
- Improved docs
The binary distribution and documentation can also be downloaded from the release.
More on these later.
Labels:
android,
AndroidViewClient,
culebra,
uiautomator
Tuesday, November 27, 2012
AndroidViewClient: UiAutomator support
AndroidViewClient v2.3.1 has been released recently providing UiAutomator compatibility, when supported by the device or emulator. UiAutomator is supported since Android API 16.
This is a great improvement over previous version in two different aspects:
This example demonstrates:
This screenshot show the state of the Buttons after the script has run.
usage: dump.py [-u|--uniqueId] [-x|--position] [-d|--content-description] [serialno]
so we can use it to verify the content of the screen. If everything went well running
dump.py --content-description
will show the View tree including also the content descriptions, as given by the following dump
UPDATE:
Changed linked version to AndroidViewClient 2.3.1 as some latest commits were not in version 2.3 as found by Durairaj.
This is a great improvement over previous version in two different aspects:
- it can now be run on non-rooted devices not demanding application modification (as previous version required to use LocalViewServer)
- the change in the backend now frees the client from port redirection, as ViewServer requests, and at the same time the performance of dumping the View tree is greatly improved
This example demonstrates:
- automatic device connection, handling command line parameters if present
- automatic View tree dump
- finding Views using regular expressions or text
- touching found Views
As a precondition to run this example, install and run AndroidSampleUI.
Zoom buttons let you increase or decrease the margins and consequently move the toggle buttons to demonstrate that they will be found whatever their coordinates are.
#! /usr/bin/env monkeyrunner
'''
Copyright (C) 2012 Diego Torres Milano
Created on Aug 31, 2012
@author: diego
'''
import re
import sys
import os
# This must be imported before MonkeyRunner and MonkeyDevice,
# otherwise the import fails.
# PyDev sets PYTHONPATH, use it
try:
for p in os.environ['PYTHONPATH'].split(':'):
if not p in sys.path:
sys.path.append(p)
except:
pass
try:
sys.path.append(os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
from com.dtmilano.android.viewclient import ViewClient, ViewNotFoundException
vc = ViewClient(*ViewClient.connectToDeviceOrExit())
# Find the 3 toggle buttons, because the first 2 change their text if they are selected
# we use a regex to find them.
# Once found, we touch them changing their state
for t in [re.compile('Button 1 .*'), re.compile('Button 2 .*'), 'Button with ID']:
try:
vc.findViewWithTextOrRaise(t).touch()
except ViewNotFoundException:
print >>sys.stderr, "Couldn't find button with text=", t
Once this script is run, ViewClient will find a device, which can be specified using its serial number in the command line invoking the script, connects to, automatically dump the tree and then use regular expressions to find two of the ToggleButtons because we couldn't use a fixed text because it changes when the button is clicked. If, for some reason the Button is not found, perhaps because it was move outside the screen using Zoom buttons, a message is printed.This screenshot show the state of the Buttons after the script has run.
More articles and examples will be coming soon, but I didn't want to miss the opportunity to introduce this new version. One of the most remarkably advantages over plain UiAutomator is the simplification of the script or test creation and the expressiveness gain of using Python instead of Java.
dump.py
dump.py is also present in AndroidViewClient examples. It now supports several command line options nowusage: dump.py [-u|--uniqueId] [-x|--position] [-d|--content-description] [serialno]
so we can use it to verify the content of the screen. If everything went well running
dump.py --content-description
will show the View tree including also the content descriptions, as given by the following dump
android.widget.FrameLayout id/no_id/1
android.widget.LinearLayout id/no_id/2
android.widget.FrameLayout id/no_id/3
android.view.View id/no_id/4
android.widget.FrameLayout id/no_id/5
android.widget.ImageView id/no_id/6
android.widget.LinearLayout id/no_id/7
android.widget.LinearLayout id/no_id/8
android.widget.TextView id/no_id/9 Sample UI v2.0
android.widget.FrameLayout id/no_id/10
android.widget.RelativeLayout id/no_id/11
android.widget.Button id/no_id/12 Show Dialog show_dialog
android.widget.LinearLayout id/no_id/13
android.widget.TextView id/no_id/14
android.widget.ToggleButton id/no_id/15 Button 1 OFF button_1
android.widget.TextView id/no_id/16 v=(75.0,82.0) lw=(115,272) ls=(115,272) wxh=(290,72) margin=(40,80) button_1_info
android.widget.ToggleButton id/no_id/17 Button 2 OFF button_2
android.widget.TextView id/no_id/18 v=(75.0,273.0) lw=(115,463) ls=(115,463) wxh=(290,72) margin=(40,80) button_2_info
android.widget.ToggleButton id/no_id/19 Button with ID button_with_id
android.widget.ZoomControls id/no_id/20 zoom
android.widget.ZoomButton id/no_id/21
android.widget.ZoomButton id/no_id/22
UPDATE:
Changed linked version to AndroidViewClient 2.3.1 as some latest commits were not in version 2.3 as found by Durairaj.
Labels:
android,
AndroidViewClient,
github,
monkeyrunner,
uiautomator
Subscribe to:
Posts (Atom)








