android自动化测试CTS源码分析之五
Posted Achillisjack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android自动化测试CTS源码分析之五相关的知识,希望对你有一定的参考价值。
6. Instrumentation
6.1 启动Instrumentation
获取adb shell am instrument –w命令后,AM.java中的onRun方法对该命令处理如下
else if (op.equals("instrument"))
runInstrument();
runInstrument方法如下,
if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi))
throw new androidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
调用ActivityManagerService的startInstrumentation方法启动Instrumentation,并且传入相关命令参数。
final long origId = Binder.clearCallingIdentity();
// Instrumentation can kill and relaunch even persistent processes
forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
"start instr");
ProcessRecord app = addAppLocked(ai, false, abiOverride);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
app.instrumentationProfileFile = profileFile;
app.instrumentationArguments = arguments;
app.instrumentationWatcher = watcher;
app.instrumentationUiAutomationConnection = uiAutomationConnection;
app.instrumentationResultClass = className;
Binder.restoreCallingIdentity(origId);
addAppLocked 方法中会调用startProcessLocked方法,到此和Activity等四大组件启动的流程完全一样。
最后在ActivityManagerService的attachApplicationLocked方法中,
Activity的启动主要调用ActivityStackSupervisor的attachApplicationLocked方法,
而Instrumentation的启动主要是调用ApplicationThreadNative的bindApplication方法,
然后跨进程调用ActivityThread的内部类ApplicationThread的bindApplication方法。
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
当然,启动Instrumentation的过程中也会创建进程。
ActivityThread的内部类ApplicationThread的bindApplication方法部分代码如下,
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
sendMessage(H.BIND_APPLICATION, data);
主要时发送handler消息切换到主线程执行。
Handler对BIND_APPLICATION消息处理如下,
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
handleBindApplication方法中有关instrumentation代码如下,
首先利用发射构造instrumentation对象,
try
java.lang.ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
catch (Exception e)
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
然后调用instrumentation对象的init方法。
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);
最后调用instrumentation对象的onCreate方法。
mInstrumentation.onCreate(data.instrumentationArgs);
6.2 Instrumentation作用
Instrumentation在自动化测试中主要作用是什么呢?
简单点说,进行自动化测试时,很多时候并不需要界面。因此可以这么说,在自动化测试中,Instrumentation作用相当于Activity。
其中的方法几乎和Activity对应的方法一摸一样。例如,
public void onCreate(Bundle arguments)
public void onStart()
public void onDestroy()
CTS的蓝牙apk的AndroidManifest.xml文件如下,
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.bluetooth">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<uses-library android:name="android.test.runner" />
</application>
<!-- This is a self-instrumenting test package. -->
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.cts.bluetooth"
android:label="CTS tests of bluetooth component">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
</manifest>
也只是将instrumentation替换了activity.
AndroidJUnitRunner和InstrumentationTestRunner都是继承于Instrumentation,作用大同小异,
但是测试原理完全一样,因此本文选择InstrumentationTestRunner进行分析。
InstrumentationTestRunner扮演的角色类似于当中的UiAutomatorTestRunner类,
通过解析获取和建立目标测试用例和测试集然后开始测试。
onCreate方法调用流程图如下,
InstrumentationTestRunner的onStart方法如下,
try
//新建打印结果对象
StringResultPrinter resultPrinter = new StringResultPrinter(writer);
//设置测试监听
mTestRunner.addTestListener(resultPrinter);
// 获取开始的系统时间
long startTime = System.currentTimeMillis();
// 开始进行测试
mTestRunner.runTest();
// 测试时间
long runTime = System.currentTimeMillis() - startTime;
// 打印测试结果
resultPrinter.printResult(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方法
finish(Activity.RESULT_OK, mResults);
6.3,测试
在InstrumentationTestRunner的onStart方法中会调用AndroidTestRunner的runTest进行测试, runTest方法如下,
public void runTest(TestResult testResult)
mTestResult = testResult;
for (TestListener testListener : mTestListeners)
mTestResult.addListener(testListener);
Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext();
for (TestCase testCase : mTestCases)
setContextIfAndroidTestCase(testCase, mContext, testContext);
setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
setPerformanceWriterIfPerformanceCollectorTestCase(testCase, mPerfWriter);
testCase.run(mTestResult);
首先设置监听,然后逐个调用测试方法。
CTS测试中,每个apk测试的TestCase完全不一样,一般都继承于AndroidTestCase,而AndroidTestCase继承于TestCase。
以蓝牙测试为例,测试类BasicAdapterTest定义如下,
public class BasicAdapterTest extends AndroidTestCase
该测试类有8个以test开头的测试用例。
具体的调用过程就不论述了,
TestCase的runBare方法如下,
public void runBare() throws Throwable
Throwable exception= null;
setUp();
try
runTest();
catch (Throwable running)
exception= running;
finally
try
tearDown();
catch (Throwable tearingDown)
if (exception == null) exception= tearingDown;
if (exception != null) throw exception;
1,在测试之前会调用setUp方法。
2,利用反射的方法进行测试用例的调用。
3,测试完成之后,会调用tearDown方法。
至于具体的测试用例,可以看蓝牙的测试。
以上是关于android自动化测试CTS源码分析之五的主要内容,如果未能解决你的问题,请参考以下文章