目录
在 AdapterView 控制器(ListView, GridView, ...)中使用 onData
Espresso (UI测试-基于Instrumentation与AndroidJunitRunner)
配置
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
JUnit4
JUnit文件夹在工程中的位置,工程创建后,在app -> src目录下
创建工程时,默认会生成一个单元测试例子ExampleUnitTest.java
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
JUnit4基础方法注解
JUnit3是通过对测试类和测试方法的命名来确定是否是测试,如测试方法必须以test开头。而在JUnit4中,是通过注解来确定的。
- @Test
说明该方法是测试方法。测试方法必须是public void,可以抛出异常。 - @Before
它会在每个测试方法执行前都调用一次。 - @After
与@Before对应,它会在每个测试方法执行完后都调用一次。 - @BeforeClass
它会在所有的测试方法执行之前调用一次。与@Before的差别是:@Before注解的方法在每个方法执行前都会调用一次,有多少个测试方法就会掉用多少次;而@BeforeClass注解的方法只会执行一次,在所有的测试方法执行前调用一次。注意该注解的测试方法必须是public static void修饰的。 - @AfterClass
与@BeforeClass对应,它会在所有的测试方法执行完成后调用一次。注意该注解的测试方法必须是public static void修饰的。 - @Ignore
忽略该测试方法,有时我们不想运行某个测试方法时,可以加上该注解。
public class TestJUnitLifeCycle {
@BeforeClass
public static void init() {
System.out.println("------init()------");
}
@Before
public void setUp() {
System.out.println("------setUp()------");
}
@After
public void tearDown() {
System.out.println("------tearDown()------");
}
@AfterClass
public static void finish() {
System.out.println("------finish()------");
}
@Test
public void test1() {
System.out.println("------test1()------");
}
@Test
public void test2() {
System.out.println("------test2()------");
}
}
JUnit4常用断言
JUnit提供了一些辅助函数,他们用来帮助我们确定被测试的方法是否按照预期正常执行,这些辅助函数我们称之为断言(Assertion)。JUnit4所有的断言都在org.junit.Assert类中,Assert类包含了一组静态的测试方法,用于验证期望值expected与实际值actual之间的逻辑关系是否正确,如果不符合我们的预期则表示测试未通过。
- assertEquals([message], expected, actual)
验证期望值与实际值是否相等,如果相等则表示测试通过,不相等则表示测试未通过,并抛出异常AssertionError。message表示自定义错误信息,为可选参数,以下均雷同。 - assertNotEquals([message], unexpected, actual)
验证期望值与实际值不相等。 - assertArrayEquals([message], expecteds, actuals)
验证两个数组是否相同 - assertSame([message], expected, actual)
断言两个引用指向同一个对象。 - assertNotSame([message], expected, actual)
断言两个引用指向不同的对象。 - assertNull([message], object)
断言某个对象为null。 - assertNotNull([message], object)
断言对象不为null。 - assertTrue([message], condition)
断言条件为真。 - assertFalse([message], condition)
断言条件为假。
Hamcrest与assertThat
JUnit4结合Hamcrest提供了一个全新的断言语法:assertThat,结合Hamcrest提供的匹配符,可以表达全部的测试思想,上面提到的问题也迎刃而解。
使用gradle引入JUnit4.12时已经包含了hamcrest-core.jar、hamcrest-library.jar、hamcrest-integration.jar这三个jar包,所以我们无需额外再单独导入hamcrest相关类库。
assertThat定义如下:
public static <T> void assertThat(String reason, T actual,
Matcher<? super T> matcher)
字符串相关匹配符
startsWith
endsWith
containsString
equalToIgnoringCase
equalToIgnoringWhiteSpace
数值相关匹配符
closeTo
greaterThan
lessThan
lessThanOrEqualTo
greaterThanOrEqualTo
集合相关匹配符
hasEntry
hasKey
hasValue
hasItem
hasItems
hasItemInArray
对象相关匹配符
notNullValue
nullValue
sameInstance
instanceOf
hasProperty
组合等逻辑匹配符
allOf
anyOf
both
either
is
isA
not
any
anything
使用如下:
assertThat("android studio", startsWith("and"));
assertThat("android studio", endsWith("dio"));
assertThat("android studio", containsString("android"));
assertThat("android studio", equalToIgnoringCase("ANDROID studio"));
assertThat("android studio ", equalToIgnoringWhiteSpace(" android studio "));
测试方法执行顺序
JUnit4提供@ FixMethodOrder注解来配置执行顺序,其可选值有:MethodSorters.NAME_ASCENDING、MethodSorters.DEFAULT、MethodSorters.JVM
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestExecOrder {
@Test
public void testD() {
System.out.println("DDDDD");
}
@Test
public void testA() {
System.out.println("AAAAA");
}
@Test
public void testB() {
System.out.println("BBBBB");
}
@Test
public void testC() {
System.out.println("CCCCC");
}
}
Espresso
Espresso是谷歌大力推荐的一套测试框架,从Android studio2.2版本开始,google就开始支持在as上espresso自动生成单元测试代码,基于Instrumentation 与AndroidJunitRunner一起工作
依赖的类库
- espresso-core 包含基础的视图匹配器,操作和断言库
- espresso-web 包含webview的测试库
- espresso-idling-resource 包含和后台作业的同步的机制
- espresso-contrib 包括DatePicker, RecyclerView and Drawer actions, accessibility checks, and CountingIdlingResource这些的扩展库
- espresso-intent 包括与意图有关的测试库
- espresso-remote Espresso多处理功能的位置
使用 Rules 创建的 JUnit4 测试实例:
@RunWith(AndroidJUnit4.class)
@LargeTest
public class HelloWorldEspressoTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
@Test
public void listGoesOverTheFold() {
onView(withText("Hello world!")).check(matches(isDisplayed()));
}
}
使用 onView 查找视图
onView(allOf(withId(R.id.my_view), withText("Hello!")))
在视图上执行操作
onView(…).perform(click());
onView(…).perform(click());
onView(…).perform(scrollTo(), click());
检查一个视图是否满足断言
onView(…).check(matches(withText("Hello!")));
在 AdapterView
控制器(ListView
, GridView
, ...)中使用 onData
AdapterView
是一个从适配器中动态加载数据的特殊控件。最常见的 AdapterView
是ListView
。与像 LinearLayout
这样的静态控件相反,在当前视图结构中,可能只加载了AdapterView
子控件的一部分, 简单的 onview()
搜索不能找到当前没有被加载的视图。Espresso 通过提供单独的 onData()
切入点处理此问题,它可以在操作适配器中有该问题的条目或该条目的子项之前将其加载(使其获取焦点)
1. 点击 Spinner 打开条目选择框
onView(withId(R.id.spinner_simple)).perform(click());
2. 点击 条目
为了条目可供选择,Spinner 用它的内容创建了一个 ListView
。list元素不会出现在视图结构中的。通过使用 onData()
我们强制将想要得到的元素加入到视图结构中。Spinner 中的元素是字符串,我们想要匹配的条目是字符串类型并且值是 “Jack”。
onData(allOf(is(instanceOf(String.class)), is("Jack"))).perform(click());
3. 验证 TextView
包含 “Americano” 字符串
onView(withId(R.id.spinnertext_simple).check(matches(withText(containsString("Jack"))));