MonkeyRunner with Robotframework - android

I am planning to use monkeyrunner scripts to do automated test cases and I want to use robotframework(I am not interested in robotium).
I saw an excellent tutorial for automating sikuli scripts with robotframework at
http://blog.mykhailo.com/2011/02/how-to-sikuli-and-robot-framework.html
Is there any way to do similar thing, with robotframework and monkeyrunner?
Here is my sample monkeyrunner script,this executes correctly when invoked with monkeyrunner.
from __future__ import with_statement
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
def testCase() :
device = MonkeyRunner.waitForConnection()
result2 = device.takeSnapshot()
# Writes the screenshot to a file
result2.writeToFile("scr.png","png")
def my_keyword():
print 'Hello, world!'
if __name__ == '__main__':
testCase()
I want to invoke the same with roboframework. and I am trying the following. I am not sure whether the following invocation is correct or not, I simply copied from sikuli automation example and modified it.
monkey_jar=/home/user/android-sdks/tools/lib/monkeyrunner.jar
guava_jar=/home/user/android-sdks/tools/lib/guavalib.jar
java -cp "robotframework-2.7.4.jar:$monkey_jar:$guava_jar" -Dpython.path="/home/user/android-sdks/tools/lib/" \
org.robotframework.RobotFramework --pythonpath=./ --outputdir=results --loglevel=TRACE $1
When I do this, I am getting the following error.
Importing test library 'MyLibrary' failed: NoClassDefFoundError: Could not initialize class com.android.monkeyrunner.MonkeyDevice
java.lang.NoClassDefFoundError:
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at MyLibrary$py.f$0(/home/user/automation/DemoScripts/MyLibrary.py:9)
at MyLibrary$py.call_function(/home/user/automation/DemoScripts/MyLibrary.py)
at robot.utils.importer$py._import$13(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py:154)
at robot.utils.importer$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py)
at robot.utils.importer$py.import_$28(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py:241)
at robot.utils.importer$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py)
at robot.utils.importer$py._import_class_or_module$4(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py:67)
at robot.utils.importer$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py)
at robot.utils.importer$py.import_class_or_module$3(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py:64)
at robot.utils.importer$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/importer.py)
at robot.run$py.main$3(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/run.py:367)
at robot.run$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/run.py)
at robot.utils.application$py._execute$10(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/application.py:87)
at robot.utils.application$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/application.py)
at robot.utils.application$py.execute_cli$5(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/application.py:45)
at robot.utils.application$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/utils/application.py)
at robot.run$py.run_cli$6(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/run.py:396)
at robot.run$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/run.py)
at robot.jarrunner$py._run$3(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/jarrunner.py:60)
at robot.jarrunner$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/jarrunner.py)
at robot.jarrunner$py.run$2(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/jarrunner.py:53)
at robot.jarrunner$py.call_function(/Users/jmalinen/Documents/workspace/robot/tmp-jar-dir/Lib/robot/jarrunner.py)
at org.robotframework.RobotFramework.run(RobotFramework.java:62)
at org.robotframework.RobotFramework.main(RobotFramework.java:37)
PYTHONPATH:
/home/user/automation/DemoScripts
/home/user/automation/DemoScripts/robotframework-2.7.4.jar/Lib/robot/libraries
/home/user/automation/DemoScripts/robotframework-2.7.4.jar/Lib
/home/user/android-sdks/tools/lib/
/home/user/automation/DemoScripts/Lib
__classpath__
__pyclasspath__/
.
/home/user/automation/DemoScripts
CLASSPATH:
robotframework-2.7.4.jar
/home/user/android-sdks/tools/lib/monkeyrunner.jar
/home/user/android-sdks/tools/lib/guavalib.jar
==============================================================================
I believe that executing monkeyrunner test cases along with roboframework is quite possible.
Any inputs?

Well, after trying for few days, I found that it is possible to use MonkeyRunner scripts with Robotframework.
In short, you can use the folllowing to launch robotframework along with monkeyrunner.
export cpath=$(echo libs/*.jar | tr ' ' ':')
java -Dpython.path=$cpath -jar robotframework-2.7.4.jar robo-tests.txt
But only problem was, monkeyrunner's main was not called, thus not initializing the ChimpChat object, which results in a null pointer exception. I fixed that in MonkeyRunner.java, and created a new monkeyrunner.jar. With this, I am able to run monkeyrunner scripts from roboframework. I will try to create a step by step tutorial and post it.

#jollychang do this way
add this to file MonkeyRunner.java
if(chimpchat == null) {
Map<String, String> chimp_options = new TreeMap<String, String>();
chimp_options.put("backend", "adb");
chimpchat = ChimpChat.getInstance(chimp_options);
MonkeyRunner.setChimpChat(chimpchat);
}
before:
JythonUtils.convertDocAnnotationsForClass(MonkeyRunner.class, dict);
then make a new monkeyrunner.jar;
need some others jar like this:
use the new monkeyrunner.jar instead of the old one.
at last: run robot with the command:
in my computer use this:
java -cp /Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools/lib/chimpchat.jar:/Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools/lib/ddmlib.jar:/Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools/lib/guavalib.jar:/Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools/lib/monkeyrunner.jar:/Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools/lib/sdklib.jar:/Users/komejun/Downloads/robotframework-2.7.5.jar -Dcom.android.monkeyrunner.bindir="/Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools" -Djava.library.path="/Users/komejun/Documents/devtool/android/android-sdk-mac_x86/tools/lib" org.robotframework.RobotFramework a.txt

Related

Python error when running SL4A script from Tasker (AttributeError: type object 'Android' has no attribute 'getIntent')

I'm trying to call a Python script from Tasker using SL4A on my Android (4.4) phone. I'm using the Run SL4A Script task for this. As a test exercise, I want to pass a string from Tasker and use it (for now just print it) in Python.
According to the link below, this can be done by setting the 'Pass Variables' field in the Run SL4A Script task and picking it up with the Android getIntent method in Python. (https://groups.google.com/forum/#!topic/taskerpro/mQIv1PBu3PU)
Here's my Python script:
import android
droid = android.Android
params = droid.getIntent().result[u'extras']
print params[0]
However when I run the task I get the following error in SL4A:
AttributeError: type object 'Android' has no attribute 'getIntent'
Anyone know why I get this and how to solve it? I can't find any reference to it elsewhere.
I don't know about calling from Tasker, but the Python script runs fine stand-alone on SL4A Release 6 and Python interpreter Py4A Release 5.
If you don't have everything installed yet, here are some some slides I recently presented at an Android developers meetup.
I think you are simply missing the parentheses in your Android imports.
I use:
import android
droid = android.Android()
you can also try:
from android import Android
droid = Android()
this makes Android an object in python properly and you should be able to call the getIntent and other functions properly.
and to save time testing if the android module is functional I also add:
def toast(x):
x = str(x)
droid.makeToast(x)
then you can pass variables to the newly defined toast(x) function.
Hope I've helped!

Can not simultaneously run monkeyrunner scripts (e.g. two monkeyrunner process) on multi device

test.py script content:
import ....
device = MonkeyRunner.waitForConnection(10,sys.argv[1])
device.startActivity(component='package/activity')
'''
some monkeyrunner events
'''
I have two device , labled device1-id and device2-id
run the monkeyrunner test.py device1-id &
run the monkeyrunner test.py device2-id &
I found some events in device2-id were sent to device1-id. I don't know why ?
I noticed some tutorials , they said , if run monkeyrunner on more devices, could write the script like below:
device1 = MonkeyRunner.waitForConnection(10,device1-id)
device2 = MonkeyRunner.waitForConnection(10,device2-id)
device1.actions
device2.actions
but this wasn't what I need. Anybody know why the monkeyrunner behaves this ?
What I need is that , I have one script , would run the same script on multi device simultaneously .
You have to specify the monkey port so you may want to use a command line argument like so
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
import sys
# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection(timeOut,"emulator-"+ sys.argv[1])
MONKEYRunner Actions . . . .
NOTE: sys.arv[0] is always the test file
Call by entering the following on the command line:
monkeyrunner test.py PortNumber
I believe that Monkeyrunner is not thread safe.
To test this, create 2 scripts, hardcoding the deviceId into each.
Start each script:
In windows, use the "start script1" and then "start script2"
In Unix use "script1 &; script2 &"
Notice that script1 fails with errors after it looks like it started working just fine. and that SCript2 also fails to do what it was intended to do because it gets commands from both windows.

Issues using a variable in monkeyrunner's ".installPackage()"

I haven't been able to find much on this topic.
I am trying to automate application testing, to where I place an app in a particular folder and I run the script: monkeyrunner.bat -v ALL myscript.py, and the script executes on whatever apk is in the folder called apkrepository. This makes it to where I do not have to alter my python script every time I test a new application.
The part where I am running into trouble is I am trying to use a variable for device1.installPackage()
See below for the code leading upto it.
installme = os.popen(r'dir C:\users\uname\desktop\apkrepository /A:-d /B').read()
print installme
# => com.application.android.apk #or whatever the package name is
filepath = r'C:\users\uname\desktop\apkrepository'
androidapp = filepath + '\\\' + installme
print androidapp
# => C:\users\uname\desktop\apkrepository\com.application.android.apk
#This exactly what I type below manually to get it to work
device1= MonkeyRunner.waitForConnection(15, "emulator-5554")
#Emulator was started in previous section of code, which is not shown here.
device1.installPackage(androidapp)
#DOES NOT WORK!!
device1.installPackage('c:\users\uname\desktop\apkrepository\com.application.android.apk')
#The only way it works seems to be to write the path in manually everytime.
I have tried many different ways to get this to work correctly, and I wasn't sure if it was something in the way(s) I was/were trying to do it. If the variable prints the correct file path I do not see how it would have issues working. This is probably something really easy, but this is where I am stuck. The error it gives:
E/Device: Error dyring Sync: Local Path does not exist. Error installing package C:\users\uname\desktop\apkrepository\com.application.android.apk
I am using windows 7 64 bit with python2.7 and the android sdk.
Thank you for any input/assistance provided! I have been stumped by this for a couple days.
Variables DO work for other places (monkeyrunner affiliated classes), like the device1.startActivity(component=runcomponent), where runcomponent is a combination of package + activity variables. Also note: I showed both device1.installPackages side by side for easy viewing. I do not run both in a row on my script.
I tried the same in linux machine, it works. Please have a look at the monkeyrunner script.
#! /usr/bin/env monkeyrunner
import re
import sys
import os
import java
import glob
import os
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
device1= MonkeyRunner.waitForConnection(15, "emulator-5554")
mydir="/home/user/apk"
os.chdir(mydir)
for files in glob.glob("*.apk"):
print files
print "path " ,os.path.abspath(mydir+"/"+files)
device1.installPackage(mydir+"/"+files)

Applying different commands at different location

I am working in Ubuntu.
I have a bunch of commands (say 10 commands like cmd1, cmd2, cmd3..............cmd10)
I want to write a python script, which can achieve the following:
It should traverse through the directory structure and apply a command
at particular directory path.
The location and the commands are already known to me.
Here is the example how, I want the script to operate.
/local/mnt/myspace/sample1$ cmd1
/local/mnt/myspace/sample2$ cmd2
/local/mnt/myspace$ cmd3
/local/mnt$cmd4
/local/mnt/myspace/sample9$ cmd 8
/local/mnt/myspace/sample3$ cmd10
can someone please help on this.
Maybe something like this:
import subprocess
import os
jobs=[
('/local/mnt/myspace/sample1', 'cmd1'),
('/local/mnt/myspace/sample2', 'cmd2'),
('/local/mnt/myspace', 'cmd3'),
('/local/mnt', 'cmd4'),
('/local/mnt/myspace/sample9', 'cmd', '8'),
('/local/mnt/myspace/sample3', 'cmd10'),
]
for job in jobs:
print "In", job[0], "executing", job[1:]
os.chdir(job[0])
subprocess.Popen(job[1:]).wait()
(just a quick shot)
Look how I have "abused" the apparent mistake at cmd 8 to show how to call programs which take parameters.
import os
pathCommands = {r'C:\Windows':'dir', r'C:\test':'cd..' }
for path, command in pathCommands.items():
os.chdir(path)
os.system(command)
Just use os.chdir(path).
Something like:
import os
from itertools import izip
paths = ('/local/mnt/myspace/sample1', '../sample2',
'../', '../', 'myspace/sample9/', '../sample3']
commands = (func1, func2, func3, func4, func5, func6)
for path, command in izip(paths, commands):
os.chdir(path)
command()
And just put each command in a function.
Edit: I thought it was different Python commands you wanted to run in different directories. If it's different external programs, use:
commands = (['cmd1', 'arg1'], ['cmd2', 'arg2'], ...)
for path, command in izip(paths, commands):
os.chdir(path)
subprocess.call(command)
No reason to use Popen and wait when this is specifically what call is for.

Where is the help.py for Android's monkeyrunner

I just can't find the help.py file in order to create the API reference for the monkeyrunner. The command described at the Android references
monkeyrunner <format> help.py <outfile> does not work when i call monkeyrunner html help.py /path/to/place/the/doc.html.
It's quite obvious that the help.py file is not found and the monkeyrunner also tells me "Can't open specified script file". But a locate on my system doesn't bring me a help.py file that has anything to do with monkeyrunner or Android.
So my question is: Where did they hide the help.py file for creating the API reference?
I cannot find it either. But one can assume that it is simply calling MonkeyRunner.help() with the passed in arguments. If you just want to get something quick use this script I created also named help.py:
#!/usr/bin/env python
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
text = MonkeyRunner.help("html");
f = open('help.html', 'w')
f.write(text);
f.close();
Run it just like any other monkeyrunner script:
$ monkeyrunner help.py
After I have all codes in my machine (i.e, repo sync), it is at mydroid/sdk/monkeyrunner/scripts along with other three:
help.py monkey_playback.py monkey_recorder.py mr_pydoc.py
This is brilliant answer https://stackoverflow.com/a/4470513/551383 but if you really want this file is in android source i.e. http://androidxref.com/4.2_r1/xref/sdk/monkeyrunner/scripts/help.py
http://androidxref.com/source/xref/sdk/monkeyrunner/scripts/help.py
I believe the documentation on the website starts from that script, but I'm pretty sure somebody edits it a bit afterwards as well.
There's an error in monkeyrunner's help documentation (monkeyrunner Built-in Help), you should use parameters in another order:
monkeyrunner help.py <format> <outfile>
And don't forget about specifying a full path to the script, if you're running it outside of the monkeyrunner.bat directory (android monkeyrunner scripts).
If you don't have Repo Sync, described by users above, you can find the sources (including help.py), for example, here: monkeyrunner scripts.
I opened an issue at Google Code (Issue 26259: monkeyrunner Built-in Help Description Error) and I hope that they'll fix it soon.

Categories

Resources