I'm tryng to test some app using monkeyrunner and AndroidViewClient, also I have used culebra to generate code, But I have this erro:
from com.dtmilano.android.viewclient import ViewClient, TextView, EditText
SyntaxError: ("mismatched input 'as' expecting COLON", ('/home/experts/AndroidViewClient-master/src/com/dtmilano/android/viewclient.py', 3795, 35, ''))
This is my script whit monkeyrunner and AndroidViewClient
import re
import sys
import os
try:
sys.path.append(os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
from com.dtmilano.android.viewclient import ViewClient, TextView, EditText
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
def main():
# Connects to the current device, returning a MonkeyDevice object
emulatorid = 'emulator-5558'
device = MonkeyRunner.waitForConnection('',emulatorid)
print "waiting for connection...\n"
package = "com.duolingo"
activity = "app.LoginActivity"
# sets the name of the component to start
runComponent = package + "/." + activity
#Runs the component
print "Start Component"
device.startActivity(component=runComponent)
MonkeyRunner.sleep(10)
vc = ViewClient(device)
vc.dump()
vc.sleep(_s)
vc.dump(window=-1)
vc.findViewWithTextOrRaise(u'GET STARTED').touch()
vc.sleep(_s)
vc.dump(window=-1)
vc.findViewWithTextOrRaise(u'Spanish', root=self.vc.findViewByIdOrRaise('id/no_id/3')).touch()
# Takes a screenshot
screenshot = device.takeSnapshot()
# Writes the screenshot to a file
screenshot.writeToFile('./device1.png','png')
print "end"
if __name__ == '__main__':
main()
If I execute this wthiout monkeyrunner it show an erro about "ViewClient(device)", This script is inside an loop (for).
EDIT:
I executed culebra and now I have my scripts running fine!! But, it works by CommandLine ($ myscripttest.py emulator-5554) If I call it using subprocess.call, where emulatorid='emulator-5554'
subprocess.call('path/script_files/myscripttest.py' + ' ' + emulatorid, shell=True)
it shows an error:
File "/path/script_files/myscripttest.py", line 9, in <module>
from com.dtmilano.android.viewclient import ViewClient
File "/usr/local/lib/python2.7/dist-packages/androidviewclient-11.0.7-py2.7.egg/com/dtmilano/android/viewclient.py", line 43, in <module>
import xml.parsers.expat
File "/usr/lib/python2.7/xml/parsers/expat.py", line 4, in <module>
from pyexpat import *
ImportError: /usr/lib/python2.7/lib-dynload/pyexpat.x86_64-linux-gnu.so: undefined symbol: XML_SetHashSalt
I verify with this code: Where is the error?
$ ldd /usr/lib/python2.7/lib-dynload/pyexpat.x86_64-linux-gnu.so
linux-vdso.so.1 => (0x00007fffe5dc2000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f55d2fd4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f55d2c0f000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f55d29e5000)
/lib64/ld-linux-x86-64.so.2 (0x00007f55d3403000)
AndroidViewClient/culebra is a monkeyrunner
replacement. You should use one or the other, not both together in a script.
culerba
or Culebra GUI will generate the correct test or script template for you that you can further customize.
All the tests and scripts generated by these tools should be executed with python 2.x.
I think I could guess what you are trying to achieve with your script and I'm going to give a step-by-step example using culebra
so you can understand how easy it is.
Launch culebra
telling that you also want to start a specific Activity
$ culebra -GuU --start-activity=com.duolingo/.app.LoginActivity --scale=0.5 -o ~/tmp/duolingo-screenshot.py
this runs the GUI (-G
), does not verify the Views in the dump (-u
), create a unit test (-U), start the Activity (--start-activity
), scales the window 50% so it fits on the screen (--scale
) and saves the test in a file (-o
).
If everything goes well, you will see Culebra GUI.
Click on the GET STARTED button on the window.
Click on Spanish
Take the desired screenshot using the context menu (alternate click on the window) or keyboard shortcut
Close the window.
At this point the test is generated and it contains something like this
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2014 Diego Torres Milano
Created on 2015-12-22 by Culebra v11.0.8
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ 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
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'forceviewserveruse': False, 'useuiautomatorhelper': False, 'ignoreuiautomatorkilled': True, 'autodump': False, 'startviewserver': True, 'compresseddump': True}
cls.options = {'start-activity': 'com.duolingo/.app.LoginActivity', 'concertina': False, 'device-art': None, 'use-jar': False, 'multi-device': False, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': 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, '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': False, 'install-apk': None, 'drop-shadow': False, 'output': None, '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
self.vc.dump(window=-1)
self.vc.findViewWithTextOrRaise(u'GET STARTED').touch()
self.vc.sleep(_s)
self.vc.dump(window=-1)
self.vc.findViewWithTextOrRaise(u'Spanish', root=self.vc.findViewByIdOrRaise('id/no_id/5')).touch()
self.vc.sleep(_s)
self.vc.dump(window=-1)
self.vc.writeImageToFile('/tmp/${serialno}-${focusedwindowname}-${timestamp}.png', 'PNG', 'None', False, False)
if __name__ == '__main__':
CulebraTests.main()
So when you run the test again, you will obtain a new screenshot.
IMPORTANT: because the test does not contain any specific information about the device or its characteristics like screen size and such and it's not using coordinates to touch but View properties like text or id you can run the same test on a very different device, like let's say a table, and it will run successfully. Even the screenshots are saved prefixed by the device's serial number so you can run all of them at the same time and on the same CI server if you like.
If you run the test more than once without reinstalling the app perhaps the second time you are not presented with the GET STARTED screen but with Pick a Daily Goal. If we wanted to consider this alternative too we can just edit the script and add the corresponding condition
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
self.vc.dump(window=-1)
if not self.vc.findViewWithText(u'Pick a Daily Goal'):
self.vc.findViewWithTextOrRaise(u'GET STARTED').touch()
self.vc.sleep(_s)
self.vc.dump(window=-1)
self.vc.findViewWithTextOrRaise(u'Spanish', root=self.vc.findViewByIdOrRaise('id/no_id/5')).touch()
self.vc.sleep(_s)
self.vc.dump(window=-1)
self.vc.writeImageToFile('/tmp/${serialno}-${focusedwindowname}-${timestamp}.png', 'PNG', 'None', False, False)
Even if you want to frame the screenshot in a device image you can do it much easier than with Android Studio where you have to re-select the options again and again. Just change the parameters of takeScreenshot
, set the STUDIO_DIR
environment variable pointing to your Studio installation
self.vc.writeImageToFile('/tmp/${serialno}-${focusedwindowname}-${timestamp}.png', 'PNG', 'nexus_5', True, True)
and voila!