天天看點

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方法去執行目标測試腳本。

運作測試腳本流程才走完萬裡長征第一步,還有一些其他的準備工作,測試腳本架構的調用還遠着呢。

繼續閱讀