Android测试用例执行线程和UI线程

在做Android的AsyncTask测试的时候,发现测试用例 在执行的时候是在一个名为“Instr: android.test.InstrumentationTestRunner”的线程中执行的,而activity是在main线程,个人这里也将其理解成UI线程。对此的原因做一些探究。
在Android测试工程的AndroidManifest.xml文件中,instrumentation标签的内容一般如下
  < instrumentation
         android:name = "android.test.InstrumentationTestRunner"
         android:targetPackage = "xxxxxx"  />
在进行测试的时候是通过android.test.InstrumentationTestRunner来运行的。这个类的父类是android.app.Instrumentation,也就是常说的Instrumentation类了。与Android中activity的生命周期类似,也是通过调用InstrumentationTestRunner的onCreate方法来开始测试的执行,onCreate中有下图所示的一部分代码
 Android测试用例执行线程和UI线程_第1张图片
前面部分主要是环境解析,加载测试类和测试用例的一些操作,可以理解通过前面的操作在testSuiteBuilder中已经保存测试类和测试用例的全部信息,然后是通过getAndroidTestRunner方法获得一个运行测试用例的AndroidTestRunner对象,然后是对mTestRunner的一些设置。关键是最后的start方法的调用。这个方法是继承自android.app.Instrumentation类,代码如下图
Android测试用例执行线程和UI线程_第2张图片

在其中生成了一个新的InstrumentationThread线程对象,并且启动了这个线程,由于是通过android.test.InstrumentationTestRunner对象来调用此方法的,因此getClass().getName()的返回结果就是字符串"android.test.InstrumentationTestRunner",所以这个新线程名就是“Instr: android.test.InstrumentationTestRunner”。再看InstrumentationThread类的源代码,这是一个Instrumentation的内部类,如下图所示
Android测试用例执行线程和UI线程_第3张图片

设置线程的运行级别,然后调用onStart方法。由于是通过InstrumentationTestRunner对象进入的调用,并且在InstrumentationTestRunner中对Instrumentation的onStart方法进行了重写,所以调用的是InstrumentationTestRunner的onStart方法,所以这时对onStart方法的执行是在新生成的“Instr: android.test.InstrumentationTestRunner”线程中。onStart代码如下
      @Override
     public   void  onStart() {
        prepareLooper();

         if  ( mJustCount  ) {
             mResults .putString(Instrumentation.  REPORT_KEY_IDENTIFIER   REPORT_VALUE_ID  );
             mResults .putInt(  REPORT_KEY_NUM_TOTAL   mTestCount  );
            finish(Activity.  RESULT_OK   mResults  );
        }  else  {
             if  ( mDebug  ) {
                Debug. waitForDebugger();
            }

            ByteArrayOutputStream byteArrayOutputStream =  new  ByteArrayOutputStream();
            PrintStream writer =  new  PrintStream(byteArrayOutputStream);
             try  {
                StringResultPrinter resultPrinter =  new  StringResultPrinter(writer);

                 mTestRunner  .addTestListener(resultPrinter);

                 long  startTime = System.currentTimeMillis();
                 mTestRunner  .runTest();
                 long  runTime = System.currentTimeMillis() - startTime;

                resultPrinter.print(  mTestRunner  .getTestResult(), runTime);
            }  catch  (Throwable t) {
                 // catch all exceptions so a more verbose error message can be outputted
                writer.println(String. format(  "Test run aborted due to unexpected exception: %s" ,
                                t.getMessage()));
                t.printStackTrace(writer);
            }  finally  {
                 mResults .putString(Instrumentation.  REPORT_KEY_STREAMRESULT  ,
                        String. format(  "\nTest results for %s=%s" ,
                         mTestRunner  .getTestClassName(),
                        byteArrayOutputStream.toString()));

                 if  ( mCoverage  ) {
                    generateCoverageReport();
                }
                writer.close();

                finish(Activity.  RESULT_OK   mResults  );
            }
        }
    }
这主要是执行测试用例,收集结果了。这也就解释了为什么测试用例执行的线程与activity运行线程不一致的了。那activity运行的线程呢?onStart方法最后调用了finish,代码如下
   public   void  finish( int  resultCode, Bundle results) {
         if  ( mAutomaticPerformanceSnapshots  ) {
            endPerformanceSnapshot();
        }
         if  ( mPerfMetrics  !=  null ) {
            results.putAll(  mPerfMetrics  );
        }
         mThread .finishInstrumentation(resultCode, results);
    }
其中有对mThread对象的使用,这是一个ActivityThread类型的对象,是Instrumentation类的私有属性,在Instrumentation类的init方法中,有对mThread字段的赋值,并且只在这里有对mThread字段的赋值操作,猜测它就代表着activity运行所在的线程,也就是UI thread。所以反推,init方法应该在OnCreate方法调用之前。

你可能感兴趣的:(多线程,android)