android自动化测试Monkeyrunner源码分析之一

时间:2021-06-17 05:39:51

1,main方法

Monkeyrunner命令的入口是MonkeyRunnerStart的main方法,

public static void main(String[] args) {
MonkeyRunnerOptions options = MonkeyRunnerOptions.processOptions(args);
if (options == null) {
return;
}
replaceAllLogFormatters(MonkeyFormatter.DEFAULT_INSTANCE, options.getLogLevel());

MonkeyRunnerStarter runner = new MonkeyRunnerStarter(options);
int error = runner.run();
System.exit(error);
}

run方法首先设置默认参数

1,解析命令行参数

2,构造MonkeyRunnerStarter对象

3,进行测试

1.1 processOptions

processOptions主要解析输入命令。

public static MonkeyRunnerOptions processOptions(String[] args)
{
int index = 0;

String hostname = DEFAULT_MONKEY_SERVER_ADDRESS;
File scriptFile = null;
int port = DEFAULT_MONKEY_PORT;
String backend = "adb";
Level logLevel = Level.SEVERE;

ImmutableList.Builder<File> pluginListBuilder = ImmutableList.builder();
ImmutableList.Builder<String> argumentBuilder = ImmutableList.builder();
while (index < args.length)
{
String argument = args[(index++)];
if ("-s".equals(argument))
{
if (index == args.length)
{
printUsage("Missing Server after -s");
return null;
}
hostname = args[(index++)];
}
•••

和monkey解析命令类似,在此就不论述了。

1.2 构造方法

MonkeyRunnerStarter的构造方法如下

public MonkeyRunnerStarter(MonkeyRunnerOptions options)
{
Map<String, String> chimp_options = new TreeMap();
chimp_options.put("backend", options.getBackendName());
this.options = options;
this.chimp = ChimpChat.getInstance(chimp_options);
MonkeyRunner.setChimpChat(this.chimp);
}

在该构造方法中,会获取ChimpChat 对象,然后赋值给chimp变量,其主要作用在后面论述。

1.3 run

run方法代码如下,

private int run()
{
String monkeyRunnerPath = System.getProperty("com.android.monkeyrunner.bindir") + File.separator + "monkeyrunner";


Map<String, Predicate<PythonInterpreter>> plugins = handlePlugins();
if (this.options.getScriptFile() == null)
{
ScriptRunner.console(monkeyRunnerPath);
this.chimp.shutdown();
return 0;
}
int error = ScriptRunner.run(monkeyRunnerPath, this.options.getScriptFile().getAbsolutePath(), this.options.getArguments(), plugins);

this.chimp.shutdown();
return error;
}

根据测试解析的测试命令,分为2种情况,

1, 如果用户在命令行运行monkeyrunner时没有提供脚本文件路径这个参数,

那么就调用ScriptRunner类的console来请求jython解析器打开一个交互窗口来让用户进行交互.

2, 如果用户在命令行运行monkeyrunner时提供了脚本路径这个参数,

那么调用的将会是ScriptRunner的run方法来将该脚本运行起来,其实里面最终调用的就是jython的解析器来运行脚本。

 

实际上,无论是打开交互console还是直接运行脚本,最终用到的都是jython解析器,并且交互console和运行脚本实质完全一样。

如果是运行脚本,调用ScriptRunner的run方法,其方法如下,

public static int run(String executablePath, String scriptfilename, Collection<String> args, Map<String, Predicate<PythonInterpreter>> plugins)
{
File f = new File(scriptfilename);


Collection<String> classpath = Lists.newArrayList(new String[] { f.getParent() });
classpath.addAll(plugins.keySet());

String[] argv = new String[args.size() + 1];
argv[0] = f.getAbsolutePath();
int x = 1;
for (String arg : args) {
argv[(x++)] = arg;
}
initPython(executablePath, classpath, argv);

PythonInterpreter python = new PythonInterpreter();
for (Map.Entry<String, Predicate<PythonInterpreter>> entry : plugins.entrySet())
{
boolean success;
try
{
success = ((Predicate)entry.getValue()).apply(python);
}
catch (Exception e)
{
LOG.log(Level.SEVERE, "Plugin Main through an exception.", e);
}
continue;
if (!success) {
LOG.severe("Plugin Main returned error for: " + (String)entry.getKey());
}
}
python.set("__name__", "__main__");

python.set("__file__", scriptfilename);
try
{
python.execfile(scriptfilename);
}
catch (PyException e)
{
if (Py.SystemExit.equals(e.type)) {
return ((Integer)e.value.__tojava__(Integer.class)).intValue();
}
LOG.log(Level.SEVERE, "Script terminated due to an exception", e);
return 1;
}
return 0;
}

该方法实例化一个jython的解析器,PythonInterpreter所在的包是“org.Python.util”。

获得jython解析器后就直接调用解析器的execfile方法去执行目标测试脚本。

运行测试脚本流程才走完万里长征第一步,还有一些其他的准备工作,测试脚本框架的调用还远着呢。