天天看点

android自动化测试Monkeyrunner源码分析之一1,main方法

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方法去执行目标测试脚本。

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