这是什么?
为您的 Android 应用测试渲染效果很难。您如何防止边距和颜色中的视觉回归悄悄出现?
迭代 UI 代码很难。您如何快速验证您的布局或视图更改在所有配置中都能正常工作?
screenshot-tests-for-android 可以通过提供一个测试框架来解决这些问题,该框架检查跨更改的视觉差异。
它是如何工作的?
screenshot-tests-for-android 在测试运行期间生成视图的确定性屏幕截图。
所谓确定性,是指您的测试的每一次运行都会生成一个像素完美的应用程序屏幕截图,就像它出现在用户的设备上一样。然后,可以使用此屏幕截图来跟踪更改并编写基于屏幕截图的测试。
这至关重要,因为现在您作为开发人员不必担心线程和计时问题。
我们通过在测试线程上模拟 Android 的 measure()
、layout()
和 draw()
来实现这一点,因此不必担心 Handler 或动画回调的影响。
我们有实用程序来生成包含所有屏幕截图的报告,我们还提供了一种将其插入到您的持续集成中的方法,要求您在首次创建屏幕截图时(或在您有意更改它们时)“记录”屏幕截图,并让您的持续集成根据记录的屏幕截图进行检查。
开始使用
首先,您需要设置 gradle 插件。
我们在 Droidcon NYC 2015 上讨论了 screenshot-tests-for-android,这是一个对所涉及概念的很好的介绍,即使 API 可能略有不同。
Gradle 设置
如果您已经在使用 Gradle 和 Android Gradle 插件,那么在 Gradle 构建中设置 screenshot-tests-for-android 非常简单。 您所需要做的就是在您的 build.gradle 中应用 screenshot-tests-for-android 插件
buildscript {
// ...
dependencies {
// ...
classpath 'com.facebook.testing.screenshot:plugin:0.14.0'
}
}
apply plugin: 'com.facebook.testing.screenshot'
此插件设置了几个 Gradle 任务
(<App Variant>
是要定位的所需变体,例如:DebugAndroidTest
)
clean<App Variant>Screenshots
- 清除上次生成的屏幕截图报告pull<App Variant>Screenshots
- 从您的设备拉取屏幕截图record<App Variant>ScreenshotTest
- 安装并运行屏幕截图测试,然后记录它们的输出以供稍后验证run<App Variant>ScreenshotTest
- 安装并运行屏幕截图测试,然后生成报告verify<App Variant>ScreenshotTest
- 安装并运行屏幕截图测试,然后根据先前记录的屏幕截图验证它们的输出
该插件还为您的测试设置了编译依赖项,因此您现在可以开始调用 Screenshot
API。 有关更多信息,请参见创建屏幕截图部分。
请看一下我们的 示例 build.gradle。
注意:默认情况下,这会覆盖您的 instrumentation 测试运行器,并且根据您的设置,这可能会导致问题。 请参见自定义测试运行器,以了解如何避免这种情况。
布局层次结构插件
我们为屏幕截图测试报告中包含的布局层次结构查看器提供了额外的插件,以添加特定于自定义视图类型和对象的信息。
只需包含依赖项
// Standard Android View Plugins (TextView, etc)
compile 'com.facebook.testing.screenshot:layout-hierarchy-common:0.14.0'
// Litho Component Plugins
compile 'com.facebook.testing.screenshot:layout-hierarchy-litho:0.14.0'
然后在您的测试类中使用与您的测试相关的插件
// Common Plugins
LayoutHierarchyDumper.addGlobalAttributePlugin(TextViewAttributePlugin.getInstance());
// Litho plugins
ComponentsConfiguration.isDebugModeEnabled = true
LayoutHierarchyDumper.addGlobalHierarchyPlugin(LithoHierarchyPlugin.getInstance())
LayoutHierarchyDumper.addGlobalAttributePlugin(LithoAttributePlugin.getInstance())
您还可以通过实现 AttributePlugin
或 HierarchyPlugin
接口来创建自己的插件。
AndroidManifest 权限
屏幕截图库需要 WRITE_EXTERNAL_STORAGE 权限。 对于库的 instrumentation 测试,请将此权限添加到 instrumentation APK 的清单中。 对于应用程序的测试,请将此权限添加到被测应用程序。
创建屏幕截图
从测试中创建屏幕截图非常容易。 您可以从 JUnit4 样式或 JUnit3 样式的 instrumentation 测试中执行此操作
public class MyTests {
@Test
public void doScreenshot() {
/*
* Create and set up your view some how. This might be inflating,
* or creating from a view class. You might want to set properties
* on the view.
*/
View view = mLayoutInflater.inflate(R.layout.my_layout, null, false);
/*
* Measure and layout the view. In this example we give an exact
* width but all the height to be WRAP_CONTENT.
*/
ViewHelpers.setupView(view)
.setExactWidthDp(300)
.layout();
/*
* Take the actual screenshot. At the end of this call the screenshot
* is stored on the device, and the gradle plugin takes care of
* pulling it and displaying it to you in nice ways.
*/
Screenshot.snap(view)
.record();
}
}
我们在 StandardAndroidViewTest.kt 中有一个示例。 您可以使用以下命令生成屏幕截图
$ ./gradlew runDebugAndroidTestScreenshotTest
例如,这是我们包含的示例测试生成的输出。
报告将保存在生成的临时目录中。 可以使用 referenceDir
参数更改输出目录。 如果该目录不存在,则将被创建。
screenshots {
referenceDir = new/target/directory
// example
// referenceDir = "$projectDir/build/reports/screenshots"
}
跨多个设备运行
在记录屏幕截图以供稍后验证时,默认情况下,屏幕截图不会严格绑定到特定设备。 如果您希望记录多个设备配置的屏幕截图并分别验证每个配置,则应在 screenshots
块中启用 multipleDevices
screenshots {
// ...
multipleDevices true
}
现在,记录的屏幕截图将基于唯一的设备标识符放置在单独的目录中。 此唯一标识符结合了 API 级别、屏幕密度类别、Google Play 服务的可用性、屏幕分辨率和设备架构。 例如,您可以看一下 示例应用程序的屏幕截图目录。
默认情况下,从所有连接的设备和模拟器中拉取屏幕截图。 为了仅从其中的一些设备拉取屏幕截图,请将 ANDROID_SERIAL
环境变量设置为您要使用的设备的序列号的逗号分隔列表(如它们出现在 adb devices
输出的第一列中)。
自定义测试运行器
默认情况下,屏幕截图测试使用专门的 InstrumentationTestRunner,它是 ScreenshotTestRunner。
但是,通常您的组织可能已经有一个自定义测试运行器。 或者更典型的是,您可能正在使用 android.support.test.runner.AndroidJUnitRunner,它提供 JUnit4 支持。 在这种情况下,您需要覆盖您的测试运行器并调用 Screenshot 库的设置和拆卸钩子。
public class MyTestRunner extends AndroidJUnitRunner {
@Override
public void onCreate(Bundle args) {
ScreenshotRunner.onCreate(this, args);
super.onCreate(args);
}
@Override
public void finish(int resultCode, Bundle results) {
ScreenshotRunner.onDestroy();
super.finish(resultCode, results);
}
}
您应该使您的 build.gradle 使用 android.testInstrumentationRunner
属性指向您的新测试运行器。
贡献
使用 Github issues 来提出请求。 我们积极欢迎 pull request;了解如何贡献。
许可 & 法律
screenshot-tests-for-android 是 Apache 2 许可的。