# UML圖

# 解釋
上圖涉及5個類:`ddmlib`提供的`TestIdentifier`類,`cts`自定義的`IRemoteTest`接口、`ITestPackageDef`接口、`TestFilter`類和`TestPackage`類。具體意義如下:
## TestIdentifier
`ddmlib`為我們提供的屬于`instrumentation`測試的`case`實體類,里面有2個屬性,case的類名和方法名。這樣我們就可以找到一個case。
## IRemoteTest
一種測試類型的接口定義,該測試類型可以直接將結果發送到監聽器,讓其處理。所以測試runner部分只管撒了歡的跑,抓結果的模塊是單獨存在的。
## ITestPackageDef
case相關信息的容器,信息從哪里來?舉個例子,寫`uiautomator case`的人都了解,我們寫的case都要打成jar包,隨著jar一起生成的還有一個與jar包名一樣的xml文件,我們的信息就是從該xml文件里來,里面定義了jar包的標識符,測試包名等信息。
## TestFilter
case的過濾器類,定義一些過濾的條件。里面有2個集合保存了要被過濾掉的case的類名或`TestIdentifier`對象,以及1個特殊的類名和方法名,這個屬性默認是為`null`,一般情況下需要你去設值,如果不設置,那么這個條件就不作為過濾的條件,來具體看看刪選的處理代碼:
~~~
public Collection<TestIdentifier> filter(Collection<TestIdentifier > tests) {
List<TestIdentifier> filteredTests = new ArrayList<TestIdentifier>(tests.size());
for (TestIdentifier test : tests) {
if (mIncludedClass != null && !test.getClassName().equals(mIncludedClass)) {
// skip
continue;
}
if (mIncludedMethod != null && !test.getTestName().equals(mIncludedMethod)) {
// skip
continue;
}
if (mExcludedClasses.contains(test.getClassName())) {
// skip
continue;
}
if (mExcludedTests.contains(test)) {
// skip
continue;
}
filteredTests.add(test);
}
Collections.sort(filteredTests, new TestIdComparator());
return filteredTests;
}
~~~
代碼塊很簡單,隨著條件分支一步一步過濾,最后剩下來的case添加到新集合中返回。
## TestPackage
包含上面3個實體對象(除了`TestFilter`),一個TestPackage代表了一個case包(jar或者apk等)相關的所有信息,例如一個`uiautomator`寫出的jar包,那么一個jar包就需要定義一個`TestPackage`對象:該jar包包含的case集合,該jar包執行的測試類型,以及jar一些相關屬性信息。有了這些就足夠了,case就可以執行run的動作了。cts執行的時候只需要得到TestPackage對象集合(代表一個個的case包對象),就可以遍歷得到所有要執行的case。
# 具體執行過程
cts中是以plan來定義要跑的case包集合,plan則是一個xml文件,里面定義了一個或多個case包的標識信息。這樣去case的目錄下就可以找到case包以及case包的xml配置文件。當我們傳入一個plan進入cts后,發生了什么?(一下方法都是CtsTest中的方法)
## buildTestsToRun方法
當測試執行的時候,cts會先調用該方法獲得所有TestPackage對象,上面說過,獲得這個就足夠了。具體該實現:
~~~
private List<TestPackage> buildTestsToRun() {
List<TestPackage> testPkgList = new LinkedList<TestPackage>();
try {
// 獲得testcases目錄下所有的xml文件解析出來的case包對象
ITestPackageRepo testRepo = createTestCaseRepo();
// 得到本次plan所需跑的case
Collection<ITestPackageDef> testPkgDefs = getTestPackagesToRun(testRepo);
for (ITestPackageDef testPkgDef : testPkgDefs) {
addTestPackage(testPkgList, testPkgDef);
}
if (testPkgList.isEmpty()) {
Log.logAndDisplay(LogLevel.WARN, LOG_TAG, "No tests to run");
}
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("failed to find CTS plan file", e);
} catch (ParseException e) {
throw new IllegalArgumentException("failed to parse CTS plan file", e);
} catch (ConfigurationException e) {
throw new IllegalArgumentException("failed to process arguments", e);
}
return testPkgList;
}
~~~
首先會去將固定路徑下的(cts根目錄下的repository\testcases)下所有xml文件解析出來,這些xml文件都是和case包一一對應的,你不能去解析jar包或者apk包吧,所以需要一個case包配置文件的存在,這樣我們讀取xml的信息就可以得到相關的信息。然后我們要篩選出本次plan需要跑的case包。
## getTestPackagesToRun方法
該方法里有4條分支,每條分支代表不同的執行任務的標識。
`1`以plan名定義的任務
`2`.以case包的uri定義的集合所定義的任務
`3`.以class定義的(一個類中的所有case)任務
`4`.以sessionID(cts為之前跑過的任務都定義了一個session)所定義的任務,這個是重跑之前的任務。
我們來只看第一種,以plan方式啟動的任務。
~~~
private Collection<ITestPackageDef> getTestPackagesToRun(ITestPackageRepo testRepo) throws ParseException, FileNotFoundException, ConfigurationException {
// use LinkedHashSet to have predictable iteration order
Set<ITestPackageDef> testPkgDefs = new LinkedHashSet<ITestPackageDef>();
if (mPlanName != null) {
Log.i(LOG_TAG, String.format("Executing CTS test plan %s", mPlanName));
File ctsPlanFile = mCtsBuildHelper.getTestPlanFile(mPlanName);
ITestPlan plan = createPlan(mPlanName);
plan.parse(createXmlStream(ctsPlanFile));
for (String uri : plan.getTestUris()) {
if (!mExcludedPackageNames.contains(uri)) {
ITestPackageDef testPackage = testRepo.getTestPackage(uri);
testPackage.setExcludedTestFilter(plan.getExcludedTestFilter(uri));
testPkgDefs.add(testPackage);
}
}
} else if (mPackageNames.size() > 0) {
......
} else if (mClassName != null) {
......
} else if (mContinueSessionId != null) {
......
} else {
// should never get here - was checkFields() not called?
throw new IllegalStateException("nothing to run?");
}
return testPkgDefs;
}
~~~
該分支中,首先根據plan名找到所有xml文件,然后解析xml文件,得到case。這樣我們就得到了ITestPackageDef對象,遍歷得到所有這樣的對象,然后將該對象集合返回。回到上面的`buildTestsToRun()`中,然后根據返回的集合元素創建`TestPackage`對象集合,這樣我們的處理過程就完成了。
- 前言
- (1)-windows下cts配置
- (2)-cts調試環境的搭建
- (3)-基礎庫tradefederation配置
- (4)-任務的添加
- (5)-9大組件配置
- (6)-任務的執行
- (7)-任務執行的調度室
- (8)-IBuildProvider
- (9)-IDeviceRecovery
- (10)-TestDeviceOptions
- (11)-ICommandOptions
- (12)-ITargetPreparer
- (13)-任務執行過程
- (14)-任務執行過程
- (15)-任務執行完
- (16)-logcat信息收集系統
- (17)-fastboot狀態監聽器
- (18)-設備恢復
- (19)-設備狀態的分類以及恢復模式的分類
- (20)-cts自身log系統
- (21)-測試結果收集系統
- (22)-自動檢測設備
- (23)-設備分類
- (24)-case的組織