Cts框架解析(24)-case的组织

UML图


Cts框架解析(24)-case的组织_第1张图片


解释


上图涉及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对象集合,这样我们的处理过程就完成了。


你可能感兴趣的:(cts)