AOSP>设计>测试(第二节)测试开发工作流

AOSP>设计>测试

第二节 测试开发工作流

一、概览

要将测试集成到平台连续测试服务,它们应该符合本页面中的准则并遵循以下建议流程。

  1. 使用 Soong 编译系统以实现简单的测试配置
  2. 使用 Test Mapping 直接在 Android 源代码树中轻松创建提交前和提交后测试规则。
  3. 使用 Atest 在本地运行测试。
  • 测试类型

    支持的测试类型包括:

    功能测试对测试用例进行通过或未通过测试的断言,而指标测试通常重复执行操作以收集时间指标。

    采用标准化的输入/输出格式后,不再需要对每个测试进行自定义结果解析和后处理,并且通用自动化测试框架可用于符合惯例的所有测试。如需了解 Android 附带的连续测试框架,请参阅 Trade Federation 概览

  • 测试用例准则

    通过连续测试服务执行的测试用例应该是封闭测试,也就是说,所有依赖项均已声明并与测试一起提供。如需了解此原则,请参阅 Google Testing Blog 网站上的“Hermetic Servers”一文。简而言之,封闭测试无需

    • 使用 Google 帐号登录
    • 配置连接(电话/Wi-Fi/蓝牙/NFC)
    • 传入测试参数
    • 由自动化测试框架对特定的测试用例执行设置或拆解

二、简单配置

每个新的测试模块都必须具有配置文件,以使用模块元数据、编译时依赖项和打包指令来指引编译系统。现在,Android 使用 Soong 编译系统来实现更简单的测试配置。

Soong 使用与 JSON 类似的 Blueprint 文件(即 .bp 文件)来对要编译的模块进行简单的声明性描述。此格式取代了以前的版本中使用的基于 Make 的系统。如需了解完整详情,请参阅持续集成信息中心上的 Soong 参考文件

要适应自定义测试或使用 Android 兼容性测试套件 (CTS),请改为按照复杂的测试配置操作。

  • 示例

    以下条目均来自这一示例 Blueprint 配置文件:/platform_testing/tests/example/instrumentation/Android.bp

    为方便起见,下面附上快照:

    android_test {
        name: "HelloWorldTests",
        srcs: ["src/**/*.java"],
        sdk_version: "current",
        static_libs: ["android-support-test"],
        certificate: "platform",
        test_suites: ["device-tests"],
    }
    

    请注意,开头的 android_test 声明表示这是一个测试。相反,如果开头为 android_app,则表示这是一个编译软件包。

  • 设置

    下面对各项设置进行了解释:

    	name: "HelloWorldTests",
    

    如果指定了 android_test 模块类型(在代码块的开头),则需要 name 设置。此设置会为模块命名,生成的 APK 将与模块名称相同,不过带有 .apk 后缀。例如,在本例中,生成的测试 apk 将命名为 HelloWorldTests.apk。此外,此设置还可以为模块定义 make 目标名称,以便您可以使用 make [options] <HelloWorldTests> 编译测试模块及其所有依赖项。

    	static_libs: ["android-support-test"],
    

    static_libs 设置指示编译系统将已命名模块的内容合并到当前模块生成的 apk 中。这意味着,每个已命名模块都会生成 .jar 文件,其内容将用于在编译期间解析类路径引用,以及合并到生成的 apk 中。

    在本例中,可能对测试普遍有用的内容如下:

    android-support-test 是 Android 测试支持库的预编译项,包括新的测试运行器 AndroidJUnitRunner:它替代了现已弃用的内置 InstrumentationTestRunner,并且支持 JUnit4 测试框架。如需了解详情,请参阅在 Android 平台上测试应用

    如果要编译一个新的插桩模块,则开始时应始终将 android-support-test 库作为测试运行器。平台源代码树还包括其他有用的测试框架,如 ub-uiautomatormockito-targeteasymock 等等。

      certificate: "platform",
    

    certificate 设置指示编译系统使用与核心平台相同的证书对 apk 进行签名。如果您的测试使用受签名保护的权限或 API,则需要此设置。请注意,此设置适合平台连续测试,但不应该用于 CTS 测试模块。另请注意,本例使用此证书设置只是为了进行说明:示例中的测试代码实际上不需要使用特殊平台证书对测试 apk 进行签名。

    如果您要为系统服务器之外的组件(也就是说,它的打包方式多少有些类似于常规应用 apk,只不过它内置到系统映像中并且可能是特权应用)编写插桩,那么插桩可能会以组件的应用软件包(请参阅下面关于清单的部分)为目标。在这种情况下,应用 makefile 可能具有自己的 certificate 设置,并且插桩模块应保留相同的设置。这是因为,要以受测应用上的插桩为目标,必须使用同一证书对测试 apk 和应用 apk 进行签名。

    在其他情况下,根本不需要此设置:编译系统将直接使用默认的内置证书(基于编译变体)对其进行签名,并且它通常称为 dev-keys

      test_suites: ["device-tests"],
    

    test_suites设置使 Trade Federation 自动化测试框架很容易发现测试。可在此处添加其他套件(如 CTS),以便共享此测试。

    	${ANDROID_PRODUCT_OUT}/testcases/HelloWorldTests/HelloWorldTests.apk
    

三、复杂配置

重要提示:只有 Android 兼容性测试套件 (CTS)测试或需要特殊设置(如停用蓝牙或收集示例数据)的测试需要遵循本部分中的说明。其他所有用例均可通过使用 Blueprint 的基于 Soong的简单测试配置来涵盖,这些 Blueprint 能够自动处理以前手动执行的大部分配置操作。

某些测试模块可能需要执行在测试用例本身内无法执行的自定义设置和拆解步骤。典型的示例可能包括:

  • 安装其他 apk(除了测试 apk 之外)
  • 将某些文件推送到设备
  • 运行命令(例如 adb shell pm …)

过去,组件团队通常依靠编写主机端测试来执行此类任务,这需要了解 Trade Federation 自动化测试框架,并且通常会提高测试模块的复杂性。

我们引入了测试模块配置的概念(借鉴于 CTS)来支持此类任务,只需几行配置即可完成上面列出的常见任务。为了达到最大的灵活性,您甚至可以实现自己的目标准备器(由 ITargetPreparerITargetCleaner 定义),并对其进行配置以在您自己的测试模块配置中使用。

测试模块的测试模块配置是添加到顶级模块源文件夹的必需 XML 文件,名为“AndroidTest.xml”。该 XML 文件遵循 Trade Federation 自动化测试框架使用的配置文件的格式。目前,通过测试模块配置处理的主要标记是“target_preparer”和“test”标记。

  • 目标准备器

    顾名思义,“target_preparer”标记会定义目标准备器(请参阅 ITargetPreparer),该目标准备器提供了一种设置方法,在执行测试模块以进行测试之前会调用该方法;如果“target_preparer”标记中引用的类也实现了 ITargetCleaner,则在测试模块完成后将调用其拆解方法。

    要使用内置的通用模块配置,请在测试模块的顶级文件夹中添加一个新文件“AndroidTest.xml”,并在该文件里填充以下内容:

    <?xml version="1.0" encoding="utf-8"?>
    <!-- [insert standard AOSP copyright here] -->
    <configuration description="Test module config for Foo">
    <!-- insert options here -->
    </configuration>
    

    例如,我们可以添加以下选项标记(在上面的“insert”注释处):

      <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
            <option name="run-command" value="settings put secure accessibility_enabled 1" />
            <option name="teardown-command" value="settings put secure accessibility_enabled 0" />
        </target_preparer>
    

    这些选项会将自动化测试框架配置为:

    1. 在调用测试模块之前,在设备上执行 shell 命令“settings put secure accessibility_enabled 1”
    2. 在测试模块完成之后,执行 shell 命令“settings put secure accessibility_enabled 0”
      在此特定示例中,分别在测试模块执行之前/之后启用/停用可访问性。通过一个简单的示例演示,可以详细介绍如何使用“option”标记。如上所示,该标记可以有两个属性:名称和值。名称属性指示选项的名称,并进一步分解成由冒号分隔的两部分:一部分是准备器的简称,另一部分是准备器提供的实际选项名称。

    值字段的确切用途取决于准备器如何定义选项:它可以是字符串、数字、布尔值,甚至可以是文件路径等等。在上面的示例中,名称“run-command:run-command”表示我们正在为由简称为“run-command”的目标准备器定义的选项“run-command”设置值;名称“run-command:teardown-command”表示我们正在为也是由简称为“run-command”的同一目标准备器定义的选项“teardown-command”设置值。下面总结了三个常见的目标准备器:

    • 类名:PushFilePreparer

      • 简称:push-file
      • 功能:将测试用例文件夹下的任意文件推送到设备上的目标
      • 注意
        • 此准备器可以从文件夹推送到文件夹,或者从文件推送到文件;也就是说,您无法将文件推送到设备上的文件夹下,您还必须指定该文件夹下的目标文件名
      • 选项
        • push:一种推送规范,格式为“/path/to/srcfile.txt->/path/to/destfile.txt”或“/path/to/srcfile.txt->/path/to/destdir/”。可以重复 此路径可能相对于测试模块目录或输出目录本身。
        • post-push:尝试完所有推送后在设备上运行的命令(使用 adb shell <your command>)。典型用例是使用 chmod 命令添加权限
    • 类名:InstallApkSetup

      • 简称:install-apk
      • 功能:将任意 apk 文件推送到设备上的目标
      • 选项
        • test-file-name:要安装到设备上的 apk 的名称。
        • install-arg:要传递给 pm install 命令的其他参数,包括前导短划线,例如“-d”。可以重复
    • 类名:RunCommandTargetPreparer

      • 简称:run-command
      • 功能:在测试模块执行之前或之后执行任意 shell 命令
      • 选项
        • run-command:要运行的 adb shell 命令。可以重复
        • teardown-command:要在拆解阶段运行的 adb shell 命令。可以重复
  • 测试类

    测试类是用于执行测试的 Trade Federation 类。

    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
      <option name="package" value="android.test.example.helloworld"/>
      <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
    </test>
    

    下面是三个常见的测试类:

    • 类名:GTest

      • 简称:gtest
      • 功能:在给定设备上运行原生测试软件包的测试。
      • 选项
        • native-test-device-path:原生测试在设备上所在的路径。
    • 类名:InstrumentationTest

      • 简称:instrumentation
      • 功能:在给定设备上运行插桩测试软件包的测试
      • 选项
        • package:要运行的 Android 测试应用的清单软件包名称。
        • class:要运行的测试类名称。
        • method:要运行的测试方法名称。
    • 类名:AndroidJUnitTest

      • 功能:使用android.support.test.runner.AndroidJUnitRunner 在给定设备上运行插桩测试软件包的测试。这是执行插桩测试的主要方法。

四、插桩测试

  • 概览

    请先阅读 developer.android.com 上的测试应用一文。请注意,在平台测试中使用插桩测试的方式有一些差异。

    总的来说,插桩测试提供了一种通过 am instrument 命令启动的特殊测试执行环境,其中目标应用进程会重启并使用基本的应用上下文进行初始化,并在应用进程虚拟机内启动插桩线程。您的测试代码在此插桩线程上开始执行,并附带一个 Instrumentation 实例,该实例可提供对应用上下文和 API 的访问权限,以操纵接受测试的应用进程。

    • 主要概念
      • 必须在应用软件包中声明插桩,方法是在应用软件包清单的 <manifest> 标记下嵌套 instrumentation 标记。
      • 严格意义来讲,应用软件包清单可以包含多个 <instrumentation> 标记,但通常不这么做。
      • 每个 <instrumentation> 必须包含:
        • android:name 属性:它应该是测试应用中包含的 Instrumentation 的子类的名称,该测试应用通常是正在使用的测试运行器,例如 android.support.test.runner.AndroidJUnitRunner
        • 必须定义 android:targetPackage 属性。其值应该设置为接受测试的应用软件包。
    • 步骤总结
    1. 下面是框架服务封闭测试的常见位置:

      	frameworks/base/core/tests/coretests
      	frameworks/base/services/tests/servicestests
      

      如果要为组件添加全新的插桩模块,请参阅

    2. 如果要将测试添加到上述某个位置,请遵循现有惯例。如果要设置一个新的测试模块,请在上述某个位置按照 AndroidManifest.xmlAndroid.mk 的设置进行操作

    3. 有关示例,请参阅 frameworks/base/core/tests/coretests/。请注意,以下行会安装额外的应用:

      	<option name="test-file-name" value="FrameworksCoreTests.apk" />
      	<option name="test-file-name" value="BstatsTestApp.apk" />
      	```
      
      
    4. 不要忘记将您的测试标记为 @SmallTest@MediumTest@LargeTest

    5. 使用 make 命令编译测试模块,例如:

      make FrameworksCoreTests -j
      
    6. 运行测试:

      • 最简单的解决方案是使用 Atest,如下所示:

        atest FrameworksCoreTests
        
      • 或者,对于更复杂的测试,请使用 Trade Federation 自动化测试框架

        make tradefed-all -j
        		tradefed.sh run template/local_min --template:map test=FrameworksCoreTests
        
    7. 如果不使用 Tradefed,请手动安装并运行测试:

      • 安装生成的 apk:
      adb install -r ${OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
      

      提示:您可以使用 adb shell pm list instrumentation 查找刚刚安装的 apk 内的插桩

      • 使用各种选项运行测试:

        • apk 中的所有测试

          adb shell am instrument -w com.android.frameworks.coretests\
          	  /android.support.test.runner.AndroidJUnitRunner
          
        • 特定 Java 软件包下的所有测试

          adb shell am instrument -w -e package android.animation \
          	  com.android.frameworks.coretests\
          	  /android.support.test.runner.AndroidJUnitRunner
          
        • 特定类下的所有测试

          adb shell am instrument -w -e class \
          	  android.animation.AnimatorSetEventsTest \
          	  com.android.frameworks.coretests\
          	  /android.support.test.runner.AndroidJUnitRunner
          
        • 特定的测试方法

          adb shell am instrument -w -e class \
          	  android.animation.AnimatorSetEventsTest#testCancel \
          	  com.android.frameworks.coretests\
          	  /android.support.test.runner.AndroidJUnitRunner
          

    测试可以使用 JUnit API 对通过或未通过测试进行显式断言;此外,任何未捕获的异常也会导致功能性故障。

    要发出性能指标,测试代码可以调用 Instrumentation#sendStatus 来发出键值对列表。请务必注意以下几点:

    • 指标可以是整数或浮点数
    • 任何非数字值都将被舍弃
    • 测试 apk 可以是功能测试或指标测试,但目前不支持混合这两种测试
  • 自插桩测试(示例)

    当启动插桩测试时,系统会重启其目标软件包,并且会注入和启动插桩代码以执行测试。一种例外情况是,这里的目标软件包不能是 Android 应用框架本身,即软件包 android,因为这样做会导致出现一种矛盾情况:需要重启 Android 框架,而正是该框架支持系统功能,包括插桩本身。

    这意味着,插桩测试无法将本身注入到 Android 框架(也称为系统服务器)以执行测试。为了测试 Android 框架,测试代码只能调用公共 API Surface,或者通过平台源代码树中可用的 Android 接口定义语言 (AIDL) 公开的 API Surface。对于此类测试,针对任何特定软件包都没有意义。因此,按照惯例会将此类插桩声明为针对其自己的测试应用软件包,如其自己的 AndroidManifest.xml 中的 <manifest> 标记所定义。

    根据要求,此类测试应用软件包还可以:

    • 捆绑测试所需的 Activity。
    • 与系统共享用户 ID。
    • 使用平台密钥进行签名。
    • 根据框架源代码而不是公共 SDK 进行编译。

    此类插桩测试有时称为自插桩。以下是平台源代码中自插桩测试的一些示例:

    本文介绍的示例是编写新的插桩测试,其中目标软件包设置为其自己的测试应用软件包。本指南使用以下测试作为示例:

    建议您先浏览代码以获得粗略的印象,然后再继续。

    • 确定源代码所在的位置

      通常,您的团队已有既定的放置模式,在既定的位置检入代码,并且在既定的位置添加测试。大多数团队拥有单个 git 代码库,或与其他团队共享一个代码库,但有一个包含组件源代码的专用子目录。

      假设组件源代码的根位置是在 <component source root>,大多数组件在该位置下具有 srctests 文件夹,以及一些其他文件(如 Android.mk,或拆分为额外的 .mk 文件)、清单文件 AndroidManifest.xml,以及测试配置文件“AndroidTest.xml”。

      由于您要添加全新的测试,因此或许需要在组件 src 旁边创建 tests 目录,并为其填充内容。

      在某些情况下,您的团队可能会在 tests 下设置更深的目录结构,因为需要将不同的测试套件打包到单独的 apk 中。在这种情况下,您需要在 tests 下创建一个新的子目录。

      不管是什么样的结构,您最终都需要在 tests 目录或新建子目录中添加文件,并且文件应类似于示例 gerrit 更改中的 instrumentation 目录中的文件。下面几部分将进一步详细说明各个文件。

    • 清单文件

      就像常规应用一样,每个插桩测试模块都需要一个清单文件。如果您将该文件命名为 AndroidManifest.xml 并在 Android.mk 旁边为测试 tmodule 提供该文件,则 BUILD_PACKAGE 核心 makefile 将自动包含该文件。

      在继续深入阅读以下内容之前,强烈建议您先查阅应用清单概览

      此文档概述了清单文件的基本组成部分及其功能。有关示例,请参阅 platform_testing/tests/example/instrumentation/AndroidManifest.xml

      为方便起见,下面附上快照:

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="android.test.example.helloworld"
      
          <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
      
          <application>
              <uses-library android:name="android.test.runner" />
          </application>
      
          <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                           android:targetPackage="android.test.example.helloworld"
                           android:label="Hello World Test"/>
      
      </manifest>
      

      关于清单文件的一些说明:

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="android.test.example.helloworld"
      

      package 属性是应用软件包名称:它是 Android 应用框架用来标识应用(在此上下文中即您的测试应用)的唯一标识符。系统中的每个用户只能安装一个采用该软件包名称的应用。

      此外,此 package 属性与 < ComponentName#getPackageName() >返回的属性相同,而且也与用来通过 adb shell 与各种 pm 子命令进行交互的属性相同。
      另请注意,虽然该软件包名称通常与 Java 软件包名称的样式相同,但是实际上两者之间没有什么关系。换句话说,您的应用(或测试)软件包可能包含具有任何软件包名称的类,但另一方面,您可以选择保持简洁性,使应用或测试中的顶级 Java 软件包名称与应用软件包名称完全相同。

      android:sharedUserId="android.uid.system"
      

      此代码声明在安装时,应该为此 apk 授予与核心平台相同的用户 ID,即运行时身份。请注意,这取决于是否使用与核心平台相同的证书为 apk 签名(请参阅上一部分中的 LOCAL_CERTIFICATE),不过它们是不同的概念:

      • 某些权限或 API 受签名保护,这需要相同的签名证书
      • 某些权限或 API 需要调用者的 system 用户身份,如果调用软件包与核心平台本身不同,则需要该软件包与 system 共享用户 ID
      <uses-library android:name="android.test.runner" />
      

      所有插桩测试都必须采用此设置,因为相关的类打包在一个单独的框架 jar 库文件中,因此在应用框架调用测试软件包时,需要额外的类路径条目。

      android:targetPackage="android.test.example.helloworld"
      

      您可能已经注意到,上述代码声明的 targetPackage 与此文件的 manifest 标记中声明的 package 属性相同。如测试基础知识中所述,此类插桩测试通常用于测试框架 API,所以除了它们本身之外,拥有特定的目标应用软件包并不是很有意义。

    • 简单配置文件

      每个新的测试模块都必须具有配置文件,以使用模块元数据、编译时依赖项和打包指令来指引编译系统。在大多数情况下,基于 Soong 的 Blueprint 文件选项就足够了。如需了解详情,请参阅简单的测试配置

    • 复杂配置文件

      重要提示:只有 CTS 测试或需要特殊设置(如停用蓝牙或收集示例数据)的测试需要遵循本部分中的说明。其他所有用例均可通过简单的测试配置来涵盖。如需了解适用于本部分的更多详细信息,请参阅复杂的测试配置。

      对于这些更复杂的用例,您还需要为 Android 的自动化测试框架 Trade Federation 编写测试配置文件。

      测试配置可以指定特殊的设备设置选项和默认参数来提供测试类。有关示例,请参阅 /platform_testing/tests/example/instrumentation/AndroidTest.xml

      为方便起见,下面附上快照:

      <configuration description="Runs sample instrumentation test.">
        <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
        <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
          <option name="test-file-name" value="HelloWorldTests.apk"/>
        </target_preparer>
        <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
        <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
        <option name="test-suite-tag" value="apct"/>
        <option name="test-tag" value="SampleInstrumentationTest"/>
      
        <test class="com.android.tradefed.testtype.AndroidJUnitTest">
          <option name="package" value="android.test.example.helloworld"/>
          <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
        </test>
      </configuration>
      

      关于测试配置文件的一些说明:

      <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="HelloWorldTests.apk"/>
      </target_preparer>
      

      上述代码告知 Trade Federation 使用指定的 target_preparer 将 HelloWorldTests.apk 安装到目标设备上。Trade Federation 中有许多目标准备器可供开发者使用,这些目标准备器可用于确保在测试执行之前正确地设置设备。

      <test class="com.android.tradefed.testtype.AndroidJUnitTest">
        <option name="package" value="android.test.example.helloworld"/>
        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
      </test>
      

      上述代码指定要用于执行测试的 Trade Federation 测试类,并传入设备上要执行的软件包,以及测试运行器框架(在本例中为 JUnit)。

      如需了解详情,请参阅测试模块配置

    • JUnit4 功能

      通过使用 android-support-test 库作为测试运行器,可以采用新的 JUnit4 样式测试类,并且示例 gerrit 更改包含 JUnit4 功能的一些非常基本的用法。有关示例,请参阅 /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java

      虽然测试模式通常特定于组件团队,但有一些普遍有用的使用模式。

      @RunWith(JUnit4.class)
      public class HelloWorldTest {
      

      JUnit4 的一个显著区别是,不再需要从通用测试基类继承测试,而是在普通 Java 类中编写测试并使用注解来指示某些测试设置和约束。在本例中,我们指示此类应作为 JUnit4 测试运行。

      @BeforeClass
      public static void beforeClass() {
      ...
      @AfterClass
      public static void afterClass() {
      ...
      @Before
      public void before() {
      ...
      @After
      public void after() {
      ...
      @Test
      @SmallTest
      public void testHelloWorld() {
      ...
      

      JUnit4 在方法上使用 @Before@After 注解来执行测试前设置和测试后拆解。同样,JUnit4 可以在方法上使用 @BeforeClass@AfterClass 注解,以便在执行测试类中的所有测试之前执行设置,并在执行测试类中的所有测试之后执行拆解。请注意,类作用域的设置和拆解方法必须是静态方法。对于测试方法,与早期版本的 JUnit 不同,它们不再需要让方法名称以 test 开头,而是每种方法都必须带有 @Test 注解。像往常一样,测试方法必须公开、不声明任何返回值、不接受任何参数,并且可能会抛出异常。

      重要提示:测试方法本身带有 @Test 注解;请注意,对于要通过 APCT 执行的测试,它们必须带有测试大小注解:在本例中,将 testHelloWorld 方法注解为 @SmallTest。该注解可以在方法作用域或类作用域内应用。

    • 访问 instrumentation

      虽然在基本的 Hello World 示例中未涉及,但是有一种相当普遍的情况是,Android 测试需要访问 Instrumentation 实例:这是核心 API 接口,可提供对应用上下文、Activity 生命周期相关测试 API 等内容的访问权限。

      因为 JUnit4 测试不再需要通用基类,所以不再需要通过 InstrumentationTestCase#getInstrumentation() 获取 Instrumentation 实例,新的测试运行器会通过 InstrumentationRegistry(用于存储插桩框架创建的上下文和环境设置)管理该实例。

      要访问 Instrumentation 类的实例,只需在 InstrumentationRegistry 类上调用静态方法 getInstrumentation()

      Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
      
    • 在本地编译和测试

      对于最常见的用例,请使用 Atest

      对于需要更繁琐自定义设置的更复杂用例,请遵循插桩说明

  • 定位应用(针对应用的插桩测试示例)

    此类插桩测试与针对常规 Android 应用的测试没有什么不同。值得注意的是,包含插桩的测试应用需要与其针对的应用使用相同的证书进行签名。

    请注意,本指南假定您已掌握平台源代码树工作流的一些相关知识。如果没有,请参阅 https://source.android.com/source/requirements。本文介绍的示例是编写新的插桩测试,其中目标软件包设置为其自己的测试应用软件包。如果您不熟悉相关概念,请仔细阅读平台测试简介

    本指南使用以下测试作为示例:

    • frameworks/base/packages/Shell/tests

    建议您先浏览代码以获得粗略的印象,然后再继续。

    • 确定源代码所在的位置

      由于此插桩测试将针对应用,因此惯例是将测试源代码放在平台源代码树中组件源代码根目录下的 tests 目录中。

      有关源代码所在位置的更多说明,请参阅自插桩测试的端到端示例

    • 清单文件

      就像常规应用一样,每个插桩测试模块都需要一个清单文件。如果您将该文件命名为 AndroidManifest.xml 并在 Android.mk 旁边为测试 tmodule 提供该文件,则 BUILD_PACKAGE 核心 makefile 将自动包含该文件。

      在继续深入阅读以下内容之前,强烈建议您先查阅应用清单概览

      此文档概述了清单文件的基本组成部分及其功能。

      要获得示例 gerrit 更改的最新版清单文件,请访问:https://android.googlesource.com/platform/frameworks/base/+/master/packages/Shell/tests/AndroidManifest.xml

      为方便起见,下面附上快照:

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.shell.tests">
      
          <application>
              <uses-library android:name="android.test.runner" />
      
              <activity
                  android:name="com.android.shell.ActionSendMultipleConsumerActivity"
                  android:label="ActionSendMultipleConsumer"
                  android:theme="@android:style/Theme.NoDisplay"
                  android:noHistory="true"
                  android:excludeFromRecents="true">
                  <intent-filter>
                      <action android:name="android.intent.action.SEND_MULTIPLE" />
                      <category android:name="android.intent.category.DEFAULT" />
                      <data android:mimeType="*/*" />
                  </intent-filter>
              </activity>
          </application>
      
          <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
              android:targetPackage="com.android.shell"
              android:label="Tests for Shell" />
      
      </manifest>
      

      关于清单文件的一些说明:

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.shell.tests">
      

      package 属性是应用软件包名称:它是 Android 应用框架用来标识应用(在此上下文中即您的测试应用)的唯一标识符。系统中的每个用户只能安装一个采用该软件包名称的应用。

      由于这是一个测试应用软件包,独立于接受测试的应用软件包,因此必须使用不同的软件包名称:一个常见的惯例是添加后缀 .test。

      此外,此 package 属性与 ComponentName#getPackageName() 返回的属性相同,而且也与用来通过 adb shell 与各种 pm 子命令进行交互的属性相同。

      另请注意,虽然该软件包名称通常与 Java 软件包名称的样式相同,但是实际上两者之间没有什么关系。换句话说,您的应用(或测试)软件包可能包含具有任何软件包名称的类,但另一方面,您可以选择保持简洁性,使应用或测试中的顶级 Java 软件包名称与应用软件包名称完全相同。

      <uses-library android:name="android.test.runner" />
      

      所有插桩测试都必须采用此设置,因为相关的类打包在一个单独的框架 jar 库文件中,因此在应用框架调用测试软件包时,需要额外的类路径条目。

      android:targetPackage="com.android.shell"
      

      上述代码将插桩的目标软件包设置为 com.android.shell.tests。通过 am instrument 命令调用插桩时,框架将重启 com.android.shell.tests 进程,并将插桩代码注入该进程以执行测试。这也意味着,测试代码可以访问在接受测试的应用中运行的所有类实例,并且或许能够操纵状态,具体取决于公开的测试钩子。

    • 简单配置文件

      每个新的测试模块都必须具有配置文件,以使用模块元数据、编译时依赖项和打包指令来指引编译系统。在大多数情况下,基于 Soong 的 Blueprint 文件选项就足够了。如需了解详情,请参阅简单的测试配置

    • 复杂配置文件

      重要提示:只有 CTS 测试或需要特殊设置(如停用蓝牙或收集示例数据)的测试需要遵循本部分中的说明。其他所有用例均可通过简单的测试配置来涵盖。如需了解适用于本部分的详细信息,请参阅复杂的测试配置

      对于更复杂的测试,您还需要为 Android 的自动化测试框架 Trade Federation 编写测试配置文件。

      测试配置可以指定特殊的设备设置选项和默认参数来提供测试类。

      要获得示例 gerrit 更改的最新版配置文件,请访问:https://android.googlesource.com/platform/frameworks/base/+/master/packages/Shell/tests/AndroidTest.xml.

      为方便起见,下面附上快照:

      <configuration description="Runs Tests for Shell.">
          <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
              <option name="test-file-name" value="ShellTests.apk" />
          </target_preparer>
      
          <option name="test-suite-tag" value="apct" />
          <option name="test-tag" value="ShellTests" />
          <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
              <option name="package" value="com.android.shell.tests" />
              <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
          </test>
      </configuration>
      

      关于测试配置文件的一些说明:

      <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="ShellTests.apk"/>
      </target_preparer>
      

      上述代码告知 Trade Federation 使用指定的 target_preparer 将 ShellTests.apk 安装到目标设备上。Trade Federation 中有许多目标准备器可供开发者使用,这些目标准备器可用于确保在测试执行之前正确地设置设备。

      <test class="com.android.tradefed.testtype.AndroidJUnitTest">
        <option name="package" value="com.android.shell.tests"/>
        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
      </test>
      

      上述代码指定要用于执行测试的 Trade Federation 测试类,并传入设备上要执行的软件包,以及测试运行器框架(在本例中为 JUnit)。

      有关测试模块配置的更多信息,请参阅此处

    • JUnit4 功能

      通过使用 android-support-test 库作为测试运行器,可以采用新的 JUnit4 样式测试类,并且示例 gerrit 更改包含 JUnit4 功能的一些非常基本的用法。

      要获得示例 gerrit 更改的最新源代码,请访问:frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.javast.java

      虽然测试模式通常特定于组件团队,但有一些普遍有用的使用模式。

      	@SmallTest
      	@RunWith(AndroidJUnit4.class)
      	public final class FeatureFactoryImplTest {
      

      JUnit4 的一个显著区别是,不再需要从通用测试基类继承测试,而是在普通 Java 类中编写测试并使用注解来指示某些测试设置和约束。在本例中,我们指示此类应作为 Android JUnit4 测试运行。

      @SmallTest 注解指定了整个测试类的测试大小:添加到此测试类中的所有测试方法都继承此测试大小注解。测试前类设置、测试后拆解和测试后类拆解:类似于 JUnit4 中的 setUptearDown 方法。 Test 注解用于对实际测试进行注解。

      重要提示:测试方法本身带有 @Test 注解;请注意,对于要通过 APCT 执行的测试,它们必须带有测试大小注解。此类注解可以在方法作用域或类作用域内应用。

       	@Before
          public void setup() {
          ...
          @Test
          public void testGetProvider_shouldCacheProvider() {
          ...
      

      JUnit4 在方法上使用 @Before 注解来执行测试前设置。还有用于执行测试后拆解的 @After,不过在本例中未使用。同样,JUnit4 可以在方法上使用 @BeforeClass@AfterClass 注解,以便在执行测试类中的所有测试之前执行设置,并在执行测试类中的所有测试之后执行拆解。请注意,类作用域的设置和拆解方法必须是静态方法。

      对于测试方法,与早期版本的 JUnit 不同,它们不再需要使方法名称以 test 开头,而是每种方法都必须带有 @Test 注解。像往常一样,测试方法必须公开、不声明任何返回值、不接受任何参数,并且可能会抛出异常。

              Context context = InstrumentationRegistry.getTargetContext();
      

      因为 JUnit4 测试不再需要通用基类,所以不再需要采用基类方法通过 getContext()getTargetContext() 来获取 Context 实例,新的测试运行器会通过 InstrumentationRegistry(用于存储插桩框架创建的上下文和环境设置)管理这些实例。通过此类,您还可以调用:

      getInstrumentation()Instrumentation 类的实例
      getArguments():通过 -e <key> <value> 传递给 am instrument 的命令行参数

    • 在本地编译和测试

      对于最常见的用例,请使用 Atest

      对于需要更繁琐自定义设置的更复杂用例,请遵循插桩说明

五、原生测试

  • 概览

    平台的原生测试通常会访问较低级别的 HAL,或针对各种系统服务执行原始 IPC。因此,测试方法通常与接受测试的服务密切相关。

    请使用 gtest 框架编译原生测试。这是与持续测试基础架构集成的先决条件。

    1. 参阅示例原生测试模块设置,位于:frameworks/base/libs/hwui/tests/unit/

    2. 测试模块配置应使用 BUILD_NATIVE_TEST 编译规则,以便自动包含 gtest 依赖项

    3. 编写测试配置。请参阅简单配置选项和复杂配置选项。

    4. 使用 mmmmma(取决于它是增量编译还是完整编译)编译测试模块,例如:

      make hwui_unit_tests -j
      
    5. 使用 Atest 在本地运行测试:

      atest hwui_unit_tests
      
    6. 使用 Trade Federation 自动化测试框架运行测试:

      make tradefed-all -j
      tradefed.sh run template/local_min --template:map test=hwui_unit_tests
      
    7. 手动安装并运行:

      • 将生成的测试二进制文件推送到设备:

        adb push ${OUT}/data/nativetest/hwui_unit_tests/hwui_unit_tests \
          /data/nativetest/hwui_unit_tests/hwui_unit_tests
        
      • 通过在设备上调用测试二进制文件执行测试:

        adb shell /data/nativetest/hwui_unit_tests/hwui_unit_tests
        

      这样将启动原生测试。您还可以将 --help 参数添加到测试二进制文件,以详细了解自定义测试执行的不同方式。最后,请参阅 gtest 高级指南,以了解更多参数及其用法。

  • 添加新的原生测试 (示例)

    如果您不熟悉 Android 平台开发,那么您可能会发现,这个从头开始添加全新原生测试的完整示例很有用,可以帮助您了解所涉及的典型工作流。此外,如果您也不熟悉 C++ 的 gtest 框架,请访问 gtest 项目网站以查看其他文档。

    本指南使用以下测试作为示例:

    Hello World 原生测试

    建议您先浏览代码以获得粗略的印象,然后再继续。

    • 确认源代码所在位置

      通常,您的团队已有既定的放置模式,在既定的位置检入代码,并且在既定的位置添加测试。大多数团队拥有单个 git 代码库,或与其他团队共享一个代码库,但有一个包含组件源代码的专用子目录。

      假设组件源代码的根位置是在 <component source root>,大多数组件在该位置下具有 srctests 文件夹,以及一些其他文件,如 Android.mk(或拆分为额外的 .bp 文件)。

      由于您要添加全新的测试,因此或许需要在组件 src 旁边创建 tests 目录,并为其填充内容。

      在某些情况下,您的团队可能会在 tests 下设置更深的目录结构,因为需要将不同的测试套件打包到单独的二进制文件中。在这种情况下,您需要在 tests 下创建一个新的子目录。

      为了进行说明,下面给出了具有单个 tests 文件夹的组件的典型目录大纲:

      \
       <component source root>
        \-- Android.bp (component makefile)
        \-- AndroidTest.bp (test config file)
        \-- src (component source)
        |    \-- foo.cpp
        |    \-- ...
        \-- tests (test source root)
            \-- Android.bp (test makefile)
            \-- src (test source)
                \-- foo_test.cpp
                \-- ...
      

      此外,下面还给出了具有多个测试源文件目录的组件的典型目录大纲:

      \
       <component source root>
        \-- Android.bp (component makefile)
        \-- AndroidTest.bp (test config file)
        \-- src (component source)
        |    \-- foo.cpp
        |    \-- ...
        \-- tests (test source root)
            \-- Android.bp (test makefile)
            \-- testFoo (sub test source root)
            |   \-- Android.bp (sub test makefile)
            |   \-- src (sub test source)
            |       \-- test_foo.cpp
            |       \-- ...
            \-- testBar
            |   \-- Android.bp
            |   \-- src
            |       \-- test_bar.cpp
            |       \-- ...
            \-- ...
      

      不管是什么样的结构,您最终都需要在 tests 目录或新建子目录中添加文件,并且文件应类似于示例 gerrit 更改中的 native 目录中的文件。下面几部分将进一步详细说明各个文件。

    • 源代码

      有关示例,请参阅 Hello World 原生测试

      带注解的源代码如下所示:

      #include <gtest/gtest.h>
      

      gtest 的头文件。请注意,使用 makefile 中的 BUILD_NATIVE_TEST 会自动解析头文件依赖项

      #include <stdio.h>
      
      TEST(HelloWorldTest, PrintHelloWorld) {
          printf("Hello, World!");
      }
      

      gtest 使用 TEST 宏编写而成:第一个参数是测试用例名称,第二个是测试名称;在结果信息中心查看时,它们与测试二进制文件名称一起形成下面的层次结构:

      <test binary 1>
      | \-- <test case 1>
      | |   \-- <test 1>
      | |   \-- <test 2>
      | |   \-- ...
      | \-- <test case 2>
      | |   \-- <test 1>
      | |   \-- ...
      | \-- ...
      <test binary 2>
      |
      ...
      

      有关使用 gtest 编写测试的更多信息,请参阅其文档:

    • 简单配置文件

      每个新的测试模块都必须具有配置文件,以使用模块元数据、编译时依赖项和打包指令来指引编译系统。在大多数情况下,基于 Soong 的 Blueprint 文件选项就足够了。如需了解详情,请参阅简单的测试配置

    • 复杂配置文件

      重要提示:只有 CTS 测试或需要特殊设置(如停用蓝牙或收集示例数据)的测试需要遵循本部分中的说明。其他所有用例均可通过简单的测试配置来涵盖。如需了解适用于本部分的详细信息,请参阅复杂的测试配置

      要改用 Trade Federation,请为 Android 的自动化测试框架 Trade Federation 编写测试配置文件。

      测试配置可以指定特殊的设备设置选项和默认参数来提供测试类。

    • 在本地编译和测试

      对于最常见的用例,请使用 Atest

      对于需要更繁琐自定义设置的更复杂用例,请遵循插桩说明

  • 原生指标测试

    原生指标测试通常用于执行硬件抽象层 (HAL) 或直接与较低级别的系统服务交互。要利用连续测试服务,应使用 google-benchmark 框架编译原生指标测试。

    1. 测试模块配置文件应使用 BUILD_NATIVE_BENCHMARK 编译规则,以便自动包含 google-benchmark 依赖项。

    2. 使用 make 命令编译测试模块:

      make -j40 bionic-benchmarks
      
    3. 使用 Trade Federation 自动化测试框架自动安装和运行:

      make tradefed-all -j
      tradefed.sh run template/local_min --template:map test=bionic-benchmarks
      
    4. 手动安装并运行,如下所示:

      • 将生成的测试二进制文件推送到设备:

        adb push ${OUT}/data/benchmarktest/bionic-benchmarks/bionic-benchmarks32 \
          /data/benchmarktest/bionic-benchmarks/bionic-benchmarks32
        
      • 通过在设备上调用测试二进制文件执行测试:

        adb shell /data/benchmarktest/bionic-benchmarks/bionic-benchmarks32
        

六、JAR主机测试

JAR (Java) 主机测试

为了实现软件代码的完全覆盖率,应执行 JAR 主机测试。请按照相关说明构建本地单元测试。要验证某项特定功能,只需编写小型单元测试即可。

  • 示例

    以下蓝图文件可提供符合您需求且可供模仿的简单 Hello World JAR 主机测试示例: platform_testing/tests/example/jarhosttest/Android.bp

    该示例对应以下位置的实际测试代码: platform_testing/tests/example/jarhosttest/test/android/test/example/helloworld/HelloWorldTest.java

    为了方便起见,我们在此处附上了该蓝图文件的快照:

     java_test_host {
        name: "HelloWorldHostTest",
    
        test_suites: ["general-tests"],
    
        srcs: ["test/**/*.java"],
    
        static_libs: [
            "junit",
            "mockito",
        ],
    }
    

    请注意,开头的 java_host_test 声明表示这是一项 JAR 主机测试。

  • 设置

    下面对各项设置进行了说明:

    	name: "HelloWorldHostTest",
    

    如果指定了 java_test_host 模块类型(在块的开头),则需要进行 name 设置。这项设置可以为您的模块命名,而且生成的 JAR 将与模块命名相同,不过其名称会带有 .jar 后缀。例如,在本例中,生成的测试 JAR 将命名为 HelloWorldHostTest.jar。此外,此设置还可以为您的模块定义 make 目标名称,以便您可以使用 make [options] <HelloWorldHostTest> 来编译测试模块及其所有依赖项。

       test_suites: ["general-tests"],
    

    test_suites 设置可让 Trade Federation 自动化测试框架轻松发现测试。可在此处添加其他套件(如 CTS),以便共享此测试。

    	static_libs: [
    	    "junit",
    	],
    

    static_libs 设置会指示编译系统将已命名模块的内容合并到当前模块的已生成的 APK 中。这意味着,每个已命名模块都会生成 .jar 文件,其内容将用于在编译期间解析类路径引用,以及合并到生成的 apk 中。

七、映射测试

Test Mapping

本文简要介绍了 Test Mapping,并说明了如何在 Android 开源项目 (AOSP) 中轻松开始配置测试。

  • 什么是 Test Mapping?

    Test Mapping 是一种基于 Gerrit 的方法,让开发者能够直接在 Android 源代码树中创建提交前规则和提交后规则,并将要测试的分支和设备的决策留给测试基础架构本身。Test Mapping 定义是名为 TEST_MAPPING 的 JSON 文件,该文件可放置在任何源目录中。

    Atest 可以使用 TEST_MAPPING 文件在相关目录中运行提交前测试。借助 Test Mapping,您只需在 Android 源代码树中进行简单的更改,即可将同一组测试添加到提交前检查。

    请参阅以下示例:

    针对 services.core 将提交前测试添加到 TEST_MAPPING

    通过导入针对 tools/dexter 将提交前的测试添加到 TEST_MAPPING

  • 定义测试组

    Test Mapping 组通过测试组进行测试。测试组的名称可以是任何字符串。例如,presubmit 可用于在验证更改时运行的测试组。postsubmit 测试可在更改合并后用于验证构建。

  • 打包构建脚本规则

    为了让 Trade Federation 自动化测试框架针对指定版本运行 Test Mapping 的测试模块,必须针对 Soong 将这些模块的 test_suite(或者针对 Make 将这些模块的 **LOCAL_COMPATIBILITY_SUITE)**设为以下两个套件之一:

    • device-tests - 针对特定设备 CPU 构建
    • general-tests - 针对任何应用二进制接口 (ABI) 构建
      如有疑问,请将 gtest 放入 device-test,并将 APK 测试放入 general-test。

    示例:

    	Android.bp: test_suites: ["device-tests"],
    	Android.mk: LOCAL_COMPATIBILITY_SUITE := device-tests
    
  • 创建 Test Mapping 文件

    对于需要测试覆盖的目录,只需添加与以下示例类似的 TEST_MAPPING JSON 文件即可。这些规则可以确保当此目录或其子目录中的任何文件被访问时,相应测试会在提交前检查中运行。

    • 举个例子

      以下是一个示例 TEST_MAPPING 文件:

      	{
      	  "presubmit": [
      	    {
      	      "name": "CtsWindowManagerDeviceTestCases",
      	      "options": [
      	        {
      	          "include-annotation": "android.platform.test.annotations.RequiresDevice"
      	        }
      	      ],
      	      "file_patterns": ["(/|^)Window[^/]*\\.java", "(/|^)Activity[^/]*\\.java"]
      	    },
      	    {
      	      "name" : "net_test_avrcp",
      	      "host" : true
      	    }
      	  ],
      	  "postsubmit": [
      	    {
      	      "name": "CtsWindowManagerDeviceTestCases"
      	    }
      	  ],
      	  "imports": [
      	    {
      	      "path": "frameworks/base/services/core/java/com/android/server/am"
      	    }
      	  ]
      	}
      
    • 设置属性

      在上面的示例中,presubmitpostsubmit 分别是每个测试组的名称。如需详细了解测试组,请参阅定义测试组

      可在 name 属性值中设置测试模块名称Trade Federation 集成测试名称(指向测试 XML 文件的资源路径,例如 uiautomator/uiautomator-demo)。请注意,不可在 name 字段中使用类 name 或测试方法 name。要缩减所运行的测试,您可以在此处使用 include-filter 等选项请参阅(include-filter 使用示例)。

      测试的 host 设置指示测试是否是在主机上运行的无设备测试。默认值为 false,表示需要有设备才能运行测试。支持的测试类型为 HostGTest(适用于原生测试)和 HostTest(适用于 JUnit 测试)。

      使用 file_patterns 属性,您可以设置正则表达式字符串列表,以匹配任何源代码文件的相对路径(相对于包含 TEST_MAPPING 文件的目录)。在上面的示例中,只有当任意以 Window 或 Activity 开头的 java 文件(该文件所在目录与 TEST_MAPPING 文件的目录或其子目录相同)发生更改时,测试 CtsWindowManagerDeviceTestCases 才会在提交前测试中运行。当反斜线 \ 包含在 JSON 文件中时,需要对其进行转义。

      借助 imports 属性,您可以包含其他 TEST_MAPPING 文件中的测试,而无需复制相应内容。请注意,导入路径的父目录中的 TEST_MAPPING 文件也将包含在内。Test Mapping 支持嵌套导入;这意味着两个 TEST_MAPPING 文件可以互相导入,并且 Test Mapping 能够正确合并随附测试。

      options 属性包含其他 TradeFed 命令行选项。

      要获取指定测试可用选项的完整列表,请运行以下命令:

      	tradefed.sh run commandAndExit [test_module] --help
      

      如需详细了解各选项的工作原理,请参阅 TradeFed 选项处理。

  • 使用 Atest 运行测试

    要在本地执行提交前测试规则,请执行以下操作:

    1. 转到包含 TEST_MAPPING 文件的目录。

    2. 运行以下命令:

      atest
      

    在当前目录及其父目录的 TEST_MAPPING 文件中配置的所有提交前测试都会运行。Atest 将针对提交前测试找到两个测试(A 和 B)并加以运行。

    要运行当前工作目录 (CWD) 和父目录中的 TEST_MAPPING 文件中的提交前测试,这是最简单的方法。Atest 会找到 CWD 及其所有父目录中的 TEST_MAPPING 文件并使用这些文件,除非 TEST_MAPPING 文件将 inherit_parent 设为 false。

    • 构建源代码

      以下示例显示了如何在源代码树中配置 TEST_MAPPING 文件。

      	src
      	├── project_1
      	│   └── TEST_MAPPING
      	├── project_2
      	│   └── TEST_MAPPING
      	└── TEST_MAPPING
      

      src/TEST_MAPPING 的内容:

      	{
      	  "presubmit": [
      	    {
      	      "name": "A"
      	    }
      	  ]
      	}
      

      src/project_1/TEST_MAPPING 的内容:

      	{
      	  "presubmit": [
      	    {
      	      "name": "B"
      	    }
      	  ],
      	  "postsubmit": [
      	    {
      	      "name": "C"
      	    }
      	  ],
      	  "other_group": [
      	    {
      	      "name": "X"
      	    }
      	  ]}
      

      src/project_2/TEST_MAPPING 的内容:

      {
        "presubmit": [
          {
            "name": "D"
          }
        ],
        "import": [
          {
            "path": "src/project_1"
          }
        ]}
      
    • 指定目标目录

      您可以指定一个目标目录,以便在该目录中运行 TEST_MAPPING 文件中的测试。以下命令可运行两个测试(A、B)。

      atest --test-mapping src/project_1
      
    • 运行提交后测试规则

      您还可以使用此命令运行在 src_path(默认为 CWD)及其父目录中的 TEST_MAPPING 中定义的提交后测试规则:

      	atest [--test-mapping] [src_path]:postsubmit
      
    • 仅运行不需要设备的测试

      要想仅运行针对主机配置的不需要设备的测试,可以为 Atest 使用选项 –host。如果没有此选项,Atest 将运行两种测试,即需要设备的测试和在主机上运行的不需要设备的测试。这两种测试将分别在两个独立的套件中运行。

      	atest [--test-mapping] --host
      
    • 识别测试组

      您可以在 Atest 命令中指定测试组。以下命令可运行与 directory src/project_1 中的文件相关的所有提交后测试,其中只包含一个测试 ( C )。

      或者,您也可以使用 :all 来运行所有测试(无论测试属于哪个组)。以下命令可运行四个测试(A、B、C、X):

      	atest --test-mapping src/project_1:all
      
    • 包含子目录

      默认情况下,如果使用 Atest 运行 TEST_MAPPING 中的测试,则系统仅运行在 CWD(或指定目录)及其父目录中的 TEST_MAPPING 文件中配置的提交前测试。如果您想运行子目录中的所有 TEST_MAPPING 文件中的测试,请使用选项 --include-subdir 强制 Atest 将这些测试一并包含在内。

      	atest --include-subdir
      

      如果未使用 --include-subdir 选项,则 Atest 将仅运行测试 A。如果使用了 --include-subdir 选项,则 Atest 将运行两个测试(A、B)。

    • 支持行级注释

      您可以添加行级 // 格式的注释,以使用后面的设置描述来充实 TEST_MAPPING 文件。ATest 和 Trade Federation 会将 TEST_MAPPING 预处理为不带注释的有效 JSON 格式。为了使 JSON 文件简洁易读,仅支持行级 // 格式的注释。

      示例:

      	{
      	  // For presubmit test group.
      	  "presubmit": [
      	    {
      	      // Run test on module A.
      	      "name": "A"
      	    }
      	  ]
      	}
      

八、运行测试(Atest)

Atest 是一个命令行工具,可让用户在本地编译、安装并运行 Android 测试,同时可以大大加快重新运行测试的速度,而无需您了解 Trade Federation 自动化测试框架命令行选项。本文介绍了如何使用 Atest 运行 Android 测试。

要了解有关如何针对 Android 编写测试的一般信息,请参阅 Android 平台测试

要了解 Atest 的总体结构,请参阅 Atest 开发者指南

要向 Atest 添加功能,请按照 Atest 开发者工作流程操作。

  • 设置您的环境

    要运行 Atest,请按照以下部分中的步骤来设置您的环境。

    • 设置环境变量
      按照打包编译脚本规则为 Soong 设置 test_suite,或为 Make 设置 LOCAL_COMPATIBILITY_SUITE。
    1. 运行 envsetup.sh

      从 Android 源代码检出的根目录处,运行:

      	source build/envsetup.sh
      
    2. 运行 lunch

      运行 $ lunch 命令以显示受支持设备菜单。找到相应设备并运行该命令。

      例如,如果您已连接 ARM 设备,请运行以下命令:

      	lunch aosp_arm64-eng
      

      这会设置运行 Atest 所需的各种环境变量,并将 Atest 命令添加到您的 $PATH

    • 基本用法

      Atest 命令采用以下形式:

      	atest [optional-arguments] test-to-run
      
      • 可选参数

        您可以在 Atest 命令中使用以下可选参数。

        长选项说明
        –build构建测试目标。
        –install在设备上安装测试软件工件 (APK)。
        –test运行测试。
        –serial在指定设备上运行测试。一次可以测试一台设备。
        –disable-teardown停用测试拆解和清理。
        info显示指定目标的相关信息并退出。
        dry-run–info 的同义词。
        –rebuild-module-info强制重建 module-info.json 文件。
        –wait-for-debugger在执行之前等待调试程序。仅用于插桩测试。
        –verbose显示 DEBUG 级别日志记录。
        generate-baseline生成基准指标,默认情况下运行 5 次迭代。
        generate-new-metrics生成新指标,默认情况下运行 5 次迭代。
        detect-regression运行回归检测算法。
        [CUSTOM_ARGS]为测试运行器指定自定义参数。
        –all-abi针对所有可用的设备架构运行测试。
        –help显示帮助消息并退出。
        ost在没有设备的情况下在主机上完全运行测试。(注意:使用 --host 运行需要设备的主机测试将失败)。

        要详细了解 -b-i-t,请参阅指定步骤:编译、安装或运行。 |

      • 要运行的测试

        您可以使用 test-to-run 运行一个或多个测试。要运行多个测试,请使用空格将各测试引用分隔开。例如:

        	atest test-to-run-1 test-to-run-2
        

        以下是一些示例:

        	atest FrameworksServicesTests
        	atest example/reboot
        	atest FrameworksServicesTests CtsJankDeviceTestCases
        	atest FrameworksServicesTests:ScreenDecorWindowTests
        

        要详细了解如何引用测试,请参阅标识测试

    • 标识测试

      您可以使用测试的模块名称、Module:Class、类名称、TF 集成测试、文件路径或软件包名称来指定 test-to-run 参数。

      • 模块名称

        要运行整个测试模块,请使用其模块名称。请输入在该测试的 Android.mkAndroid.bp 文件中的 LOCAL_MODULELOCAL_PACKAGE_NAME 变量中显示的名称。

        注意:使用 TF 集成测试运行直接集成到 TradeFed 中的非模块测试。

        示例:

        	atest FrameworksServicesTests
        	atest CtsJankDeviceTestCases
        
      • Module:Class

        要运行模块内的单个类,请使用 Module:ClassModule模块名称中所述。Class 是 .java 文件中测试类的名称,可以是完全限定的类名,也可以是基本名称。

        示例:

        	atest FrameworksServicesTests:ScreenDecorWindowTests
        	atest FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
        	atest CtsJankDeviceTestCases:CtsDeviceJankUi
        
      • 类名称

        要在不明确声明模块名称的情况下运行单个类,请使用类名称。

        示例:

        	atest ScreenDecorWindowTests
        	atest CtsDeviceJankUi
        

        建议尽可能使用 Module:Class 引用,因为如果没有声明任何模块,Atest 将需要更多时间来搜索完整源代码树以查找可能的匹配项。

        示例(从最快到最慢排序):

        	atest FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
        	atest FrameworksServicesTests:ScreenDecorWindowTests
        	atest ScreenDecorWindowTests
        
      • TF 集成测试

        要运行直接集成到 TradeFed(非模块)中的测试,请输入 tradefed.sh list configs 命令的输出中显示的名称。例如:

        要运行 reboot.xml测试 ,请使用以下命令:

        	atest example/reboot
        

        要运行 native-benchmark.xml测试 ,请使用以下命令:

        	atest native-benchmark
        
      • 文件路径

        通过输入相应测试文件或目录的路径,您既可以运行基于模块的测试,也可以运行基于集成的测试。您还可以通过指定单个类的 Java 文件的路径来运行该类。同时支持相对路径和绝对路径。

        示例:通过路径运行 CtsJankDeviceTestCases 模块的两种方法

        1. 从 android repo-root 运行模块:

          	atest cts/tests/jank
          
        2. 从 android repo-root/cts/tests/jank 运行:

          	atest .
          

        示例:通过路径运行 CtsJankDeviceTestCases 模块内的特定类。从 android repo-root 运行:

        	atest cts/tests/jank/src/android/jank/cts/ui/CtsDeviceJankUi.java
        

        示例:通过路径运行集成测试。从 android repo-root 运行:

        	atest tools/tradefederation/contrib/res/config/example/reboot.xml
        
      • 软件包名称

        Atest 支持按软件包名搜索测试。

        示例:

        	atest com.android.server.wm
        	atest android.jank.cts
        
    • 指定步骤:编译、安装或运行

      您可以使用 -b、-i 和 -t 选项指定要运行的步骤。如果未指定选项,则运行所有步骤。

      注意:您可以单独运行 -b 和 -t,但 -i 需要 -t 才能运行。

      • 仅编译目标:atest -b test-to-run
      • 仅运行测试:atest -t test-to-run
      • 安装 apk 并运行测试:atest -it test-to-run
      • 编译并运行,但不安装:atest -bt test-to-run

      Atest 可以强制测试跳过清理/拆解步骤。许多测试(例如 CTS)会在运行完测试后清理设备,因此如果没有 --disable-teardown 参数,尝试使用 -t 重新运行测试将失败。请在使用 -t 之前先使用 -d 跳过测试清理步骤以便进行循环测试。

      	atest -d test-to-run
      	atest -t test-to-run
      

      注意:-t 既不执行设置/安装操作,又不执行拆解/清理操作,因此您可以使用 atest -t test-to-run 重新运行测试任意次数。

    • 运行特定方法

      您可以运行测试类中的特定方法。虽然需要构建整个模块,但这么做可以缩短运行测试所需的时间。要运行特定方法,请使用任何受支持的类标识法(Module:Class、文件路径等)来标识类,并附加相应方法的名称。

      	atest reference-to-class#method1
      

      您可以使用逗号指定多个方法。

      	atest reference-to-class#method1,method2,method3
      

      示例:

      	atest com.android.server.wm.ScreenDecorWindowTests#testMultipleDecors
      	atest FrameworksServicesTests:ScreenDecorWindowTests#testFlagChange,testRemoval
      

      以下两个示例展示了用于运行单个方法 testFlagChange 的首选方式。之所以首选这些示例而不是只使用类名称,是因为指定模块或 Java 文件位置可以让 Atest 更快地找到测试:

      1. 使用 Module:Class

        	atest FrameworksServicesTests:ScreenDecorWindowTests#testFlagChange
        
      2. 从 android repo-root 运行:

        	atest frameworks/base/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java#testFlagChange
        

      可以从不同的类和模块运行多个方法:

      	atest FrameworksServicesTests:ScreenDecorWindowTests#testFlagChange,testRemoval ScreenDecorWindowTests#testMultipleDecors
      
    • 运行多个类

      要运行多个类,请使用空格将这些类分隔开,如同运行多个测试。Atest 可有效地构建和运行类,因此指定模块中的一部分类可以提高性能(与运行整个模块相比)。

      示例:

      • 同一模块中的两个类:
      	atest FrameworksServicesTests:ScreenDecorWindowTests FrameworksServicesTests:DimmerTests
      
      • 不同模块中的两个类:
      	atest FrameworksServicesTests:ScreenDecorWindowTests CtsJankDeviceTestCases:CtsDeviceJankUi
      
    • 运行原生测试

      Atest 可以运行原生测试。

      示例:

      • 输入测试:

        	atest -a libinput_tests inputflinger_tests
        

      使用 -a 可针对所有可用的设备架构(在此示例中为 armeabi-v7a(ARM 32 位)和 arm64-v8a(ARM 64 位))运行测试。

    • 检测指标回归

      您可以生成打补丁前指标或打补丁后指标,而无需运行回归检测。您可以指定迭代次数,但默认值为 5。

      示例:

      	atest test-to-run --generate-baseline [optional-iteration]
      	atest test-to-run --generate-new-metrics [optional-iteration]
      

      可以通过三种方法运行本地回归检测:

      1. 生成基准(打补丁前)指标并将其放在文件夹中。Atest 按照指定的迭代次数运行测试,生成打补丁后指标,并将这些指标与现有指标进行比较。

        例如:

        	atest test-to-run --detect-regression /path/to/baseline --generate-new-metrics [optional-iteration]
        
      2. 使用包含以前生成的打补丁后指标的文件夹,Atest 会运行测试并进行 n 次迭代,生成一组新的打补丁前指标,并将这些指标与所提供的那些指标进行比较。

        注意:开发者需要将设备/测试还原为打补丁前状态以生成基准指标。

        例如:

        	atest test-to-run --detect-regression /path/to/new --generate-baseline [optional-iteration]
        
      3. 使用同时包含打补丁前指标和打补丁后指标的两个文件夹,Atest 会运行回归检测算法而不进行任何测试。

        示例:

        	atest --detect-regression /path/to/baseline /path/to/new
        

九、Android Test Station

  • 用户指南
    Android Test Station
  • 版本说明 (略)
  • 常见问题解答
    ATS常见问题
    • 如何运行其他版本的ATS?

      您可以在启动时使用–tag更改ATS的版本。

      	mtt start --tag=prod_R11.202011.002
      

      --tag的可用选项可以在ATS云存储库中的“标签”列下找到。常用的标签有:

      • ·prod· :最新的生产版本(默认使用)
      • ·latest· :每日开发人员构建(不稳定,但包含最新更改和错误修复)
      • ·prod_Rxx.xxxxxx.xxx· :用于特定版本号
    • 如何修复LowDiskSpaceException?

      执行测试运行时,您可能会在主机日志中看到以下错误:

      	com.android.tradefed.util.FileUtil$LowDiskSpaceException: Available space on /data/tmp is 0.00 MB. Min is 100 MB.
      

      此错误是由于主机存储空间不足。 /data/tmp是Test Station正在使用的Docker数据卷内的文件夹。您可以通过运行docker inspect mtt-data找到实际位置。

      要解决此问题,您可以使用以下方法删除旧的测试运行文件:

      	docker exec -it mtt find /data/app_default_bucket/test_runs/ -type d -ctime +[number of days] -exec rm -rf {} +
      

      其中[天数]是要保留的测试运行文件的天数。早于该值的测试运行文件将被删除。

      或者,您可以通过设置Docker守护程序的·–data-root·选项备份数据并更改数据卷位置。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值