[译] ConstraintLayout 可视化[Design]编辑器(这到底是什么)[第四部分]
- 原文地址:Testing Views in Isolation with Espresso
- 原文作者:Ataul Munim
- 译文出自:掘金翻译计划
- 译者:yazhi1992
- 校对者:lovexiaov, Phoenix
使用 Espresso 隔离测试视图
在这篇文章里,我将会告诉你为何并且如何使用 Espresso 在 Android 设备上测试你的自定义视图。
你可以使用 Espresso 来一次性测试所有界面或流程。这些测试用例会启动某个页面,并像用户一般执行操作,包括等待数据的加载或跳转到其他页面。
这样做是非常有用的,因为你需要端到端的测试用例来验证常见的用户使用流程。这些自动化测试应该定期地执行,从而可以节约手工 QA 的时间来进行探索性测试。
即便如此,这些不是可以频繁运行的测试。运行一整套可能会花费数小时的时间(想象一下验证媒体内容的脱机同步),所以你可以选择在夜间运行它们。
这很困难,因为这些类型的测试包含了多个潜在的故障点。理想情况是,当某个测试失败时,你会希望它是由于单个逻辑断言而导致的。
大多数(或者说很多)可以引入的回归测试点都在 UI 上。这些问题很可能是十分细微的,以至于我们在添加新特性时并不会注意到,但是敏锐的 QA 团队却往往可以。
这样就浪费太多时间了。
你能做些什么?
让我们来看下如何使用 Espresso 来测试正确地绑定了数据的视图。
在 Novoda 里,我们编写的大多数视图都是继承自 Android 已有的 View 和 ViewGroup 类。这些视图一般只会暴露了一到两个方法用来绑定回调函数和数据对象/视图模型,如下所示:
public class MovieItemView extends RelativeLayout {
private TextView titleTextView;
private Callback callback;
public void attach(Callback callback) {
this.callback = callback;
}
public void bind(Movie movie) {
titleTextView.setText(movie.name());
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
callback.onClick(movie);
}
});
}
}
他们将 UI 的逻辑部分组合在一起,并且通常还包含来自业务领域的命名规范。在
Novoda 的页面布局中你很少会看到“原始”的 Android 视图。
让我们使用 BDD 风格来编写这些视图测试,比如“当 MovieItemView 被绑定到 Edward Scissorhands 上,标题就被设置成 Edward Scissorhands”或者“MovieItemView 被绑定到 Edward Scissorhands 上,当点击视图时,onClick(Edward Scissorhands) 就会被调用”,等等。(译者注:BDD(Behaviour Driven Development),倾向于断言被测对象的行为特征而非输入输出。一个典型的 BDD 的测试用例包活完整的三段式上下文,测试大多可以翻译为 Given-When-Then
的格式,即某种场景下,发生了事件,导致了什么结果。)
难道不能使用单元测试来捕获这些问题吗?
如果你正在使用像 MVP 或者 MVVM 这样可被单元测试的表现模式,为什么还需要 Espresso 来运行这些测试呢?
首先,让我们来看一下展示信息的流程并且描述一下目前所能做的测试,然后再看看使用 Espresso 测试能多做些什么。
Presenters 订阅发送事件的数据生成器
事件可以处于
加载中
,空闲
或错误
状态,并且可能带有要展示的数据Presenters 将使用
display(List<Movie>)
,displayCachedDataWhileLoading(List<Movie>)
或displayEmptyScreen()
等方法将这些事件转发给“displayers”(MVP 中的“View”)。displayers 的具体实现类将显示/隐藏 Android 视图,并执行诸如
moviesView.bind(List<Movie>)
之类的操作
你可以对 presenters 进行单元测试,验证是否调用了 displayers 正确的方法并且带有正确的参数。
你可以用相同的方式测试 displayers 吗?是的,你是可以模拟 Android 视图,并验证是否调用了正确的方法。但这样的粒度并不是我们想要的:
displayer 可能确实构建或更新了 RecyclerView 或 ViewPager 适配器,但这并不代表显示了正确的内容。
Android 视图是通过在代码中加载 XML(布局和样式)设置的;验证方法的调用不足以断言显示的内容是否正确
设置测试用例
就从使用 espresso-support
这个库开始吧。
在你的 build.gradle(JCenter 可用)里添加依赖
debugCompile 'com.novoda:espresso-support-extras:0.0.3'
androidTestCompile 'com.novoda:espresso-support:0.0.3'
extras
依赖包中包含了 ViewActivity
,在测试时需要将其添加到你的应用中。你可以在该 Activity 持有想要使用 Espresso 测试的单一视图。
核心部分(包含自定义测试规则)只需要作为 androidTest
依赖中的一部分。
ViewTestRule
使用方法与 ActivityTestRule
类似。只不过是将传递的参数从想要启动的 Activity 类替换成了包含你想要测试的视图的布局文件:
@RunWith(AndroidJUnit4.class)publicclassMovieItemViewTest{
@Rule
public ViewTestRule<MovieItemView> viewTestRule=newViewTestRule<>(R.layout.test_movie_item_view);
...
你可以使用 ViewTestRule<MovieItemView>
指定根布局的视图类型。
ViewTestRule
继承了 ActivityTestRule<ViewActivity>
,所以它总会打开 ViewActivity
。 getActivityIntent()
被重写了,所以你可以将 R.layout.test_movie_item_view
作为 Intent 的附加数据传递给 ViewActivity
。
你可以在测试中使用 Mockito 代替回调函数。
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock
MovieItemView.Listener movieItemListener;
@Before
publicvoidsetUp(){
MovieItemView view = viewTestRule.getView();
view.attachListener(movieItemListener);
...
}
ViewTestRule 有一个 bindViewUsing(Binder)
方法,该方法会返回视图的引用,以便你与之进行交互。当你使用 viewTestRule.getView()
直接访问视图时,你会希望与视图的所有交互都是在主线程上执行的,而非测试线程。
@Before
public void setUp() {
MovieItemView view = viewTestRule.getView();
view.attachListener(movieItemListener);
viewTestRule.bindViewUsing(new ViewTestRule.Binder<MovieItemView>() {
@Override
public void bind(MovieItemView view) {
view.bind(EDWARD_SCISSORHANDS);
}
});
}
准备测试
从用户的角度上来看,应用其实只做了两件事情:
展示信息
响应用户的操作
要为这两种情况编写测试,你可以先从使用标准的 Espresso ViewMatchers 和 ViewAssertions 语句断言是否显示正确的信息开始:
@Test
public void titleSetToMovieName() {
onView(withId(R.id.movie_item_text_name))
.check(matches(withText(EDWARD_SCISSORHANDS.name)));
}
接着,你应该确保用户的操作触发了正确的点击事件,并且具有正确的参数:
@Test
public void clickMovieItemView() {
onView(withClassName(is(MovieItemView.class.getName())))
.perform(click());
verify(movieItemListener)
.onClick(eq(EDWARD_SCISSORHANDS));
}
到这里就完成了,希望这些知识对你有用。
在接下来的文章里,我会介绍如何使用 Espresso 测试视图时支持 TalkBack 服务(译者注:Talkback 是一款由谷歌官方开发的系统工具软件,它的定位是帮助盲人或者有视力障碍的用户提供语言辅助)。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、React、前端、后端、产品、设计 等领域,想要查看更多优质译文请持续关注 掘金翻译计划。
[译] ConstraintLayout 可视化[Design]编辑器(这到底是什么)[第四部分]的更多相关文章
- 可视化HTML编辑器
[荐] 可视化HTML编辑器 CKEditor CKEditor是新一代的FCKeditor,是一个重新开发的版本.CKEditor是全球最优秀的网页在线文字编辑器之一,因其惊人的性能与可扩展性而广泛 ...
- 【ASP.NET 插件】分享一个可视化HTML编辑器 CKEditor.NET
因为公司网站的可视化HTML编辑器IE兼容性问题,js报错不能使用,于是在网上找到了个还行的,图片本地上传的话直接把图片拖到编辑窗口就可以了.这个编辑器是在开源中国看到的,个人觉得还不错! CKEdi ...
- 基于 ReactJS 开发简单的可视化业务编辑器 01
线上可以看的,跟github上的代码不一样的:https://whensea.com/wfd/ 程序中经常有一些业务需要定制化,我定制化这些业务的方式主要是基于工作流.配置等方式.由于个人水平限制并不 ...
- Bootstrap 可视化HTML编辑器,summernote
Bootstrap 可视化HTML编辑器之summernote,用其官网上的介绍就是"Super Simple WYSIWYG editor",不过在我看来,与bootstrap中 ...
- [译]如何在Unity编辑器中添加你自己的工具
在这篇教程中你会学习如何扩展你的Unity3D编辑器,以便在你的项目中更好的使用它.你将会学习如何绘制你自己的gizmo,用代码来实现创建和删除物体,创建编辑器窗口,使用组件,并且允许用户撤销他们所作 ...
- TinyMCE logo 可视化HTML编辑器 TinyMCE
TinyMCE是一个轻量级的基于浏览器的所见即所得编辑器,支持目前流行的各种浏览器,由JavaScript写成.功能配置灵活简单(两行代码就可以 将编辑器嵌入网页中),支持AJAX.另一特点是加载速度 ...
- CKEditor 4.5 beta 发布,可视化 HTML 编辑器
分享 <关于我> 分享 [中文纪录片]互联网时代 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...
- [译]angularjs directive design made easy
原文: http://seanhess.github.io/2013/10/14/angularjs-directive-design.html AngularJS directives很酷 Angu ...
- Unity3D研究院之使用Animation编辑器编辑动画(五十四)
Unity提供了Animation编辑器,它可以为我们编辑物理动画.举个例子比如场景中有一个来回摇动的秋千,这个秋千在项目中完全只起到衬托作用,它不会与别的游戏对象有任何交互.如果这个秋千也用代码来 ...
随机推荐
- CentOS下如何用nmon收集系统实时运行状况
#赋予执行权限 chmod +x nmon 执行./nmon可以查看实时的系统状态有提示的,d看磁盘,n看网络,c看cpu #如果不想看实时的,想收集系统长时间运行情况然后分析,可用这个 nohup ...
- java46
1.迭代器遍历 import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public c ...
- 老猿学5G扫盲贴:中国移动网络侧CHF主要功能及计费处理的主要过程
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一. ...
- Android的intent
title: Android基础01 date: 2020-02-15 17:17:04 tags: 1.Intent Intent可以让活动进行跳转.使用方式有两种,一种是显式,另一种是隐式. 1. ...
- bugku login4
(前排提示:这次思路写的极不清晰,可能只有我自己看的懂,打个预防针QAQ) 首先看题: 扫描,拿到了 .index.php.swp 这个文件是可以复原的. 上面的是重要的源码.审计之后发现这是CBC加 ...
- Linux 挂载,卸载光盘
首先我们点击虚拟机 点击设置 选择CD 接着我们将设备状态两个勾都勾选,并且ISO映像文件选择我们需要挂载的光盘 点击了确定之后,我们到centos7的命令行下 1,创建挂载目录 mkdir /mnt ...
- Aizu2970 Permutation Sort
题目大意 给你两个 \(n\) 个整数的排列,第一个排列表示原排列,第二个排列表示第 \(i\) 个数可以和i变成第 \(g_i\) 个数,问,最少对所有数进行几次操作可以使原排列变为有序的排列. 题 ...
- word IF嵌套实现登记学生成绩(合格,良好,优秀)
word IF函数 IF语法 IF(判断条件,条件成立的动作,条件不成立的动作),以逗号(英文)分隔 例:=IF( 0 < 1 , "good" , "bad&qu ...
- 封装事件订阅来进行非父子组件的传值(React)
const list={} // 将事件名和事件函数装进事件池里 function $on(name,func) { if(!name || !func) return; if(!Object.key ...
- 关于golang的time包总结
目录 前言 time包详解 总结 前言 各种编程语言都少不了与时间有关的操作,因为很多判断都是基于时间,因此正确和方便的使用时间库就很重要额. golang提供了import "time&q ...