需要解决的问题:
1. 像powermock,Robolectric,Mockito的关系是什么,与junit的关系又如何
2. 每个框架可以做、不可以做的有哪些
3. 如何结合它们进行测试
4. 与androidTest的关系
所有单元测试的框架都基于junit来,使用junit提供的基础服务
robolectric 用于模拟android环境的,可以提供在as下运行
要使用@RunWith(RobolectricGradleTestRunner.class)声明在类头
对于每一个测试类或方法,都可以使用注解 Config 来配置特殊的参数,方法中的配置可以覆盖类头声明的配置,列举如下:
1. @Config(constants=BuildConfig.class): 指定一个BuildConfig,一般用于类声明
2. @Config(sdk=INT): 声明测试方法中使用的SDK版本
3. @Config(application=XXX.class): 声明使用Application
目前对21以上的版本,robolectric有点不太兼容,但可以通过config指定sdk版本
Robolectric.setupActivity: 模拟一个activity
mockito: 用于类模拟等
powermock是基于mockito的一个扩展
Dependency dependency = PowerMockito.mock(Dependency.class): 模拟一个类,但其实际内容都不会真正执行,所有的成员都不会初始化,对象会为null,简单类型会为基本的默认属性,如0,false等
可以使用doRealCall去调用真正的方法,但是模拟出来的类依然不会真正实例化,所以需要真实调用的方法里如果使用了类里面的成员,都会有问题
可以使用when().thenReturn来修改一个方法的返回值,when里面传入一个模拟对象的方法,假如方法有参数,则参数也需要传进去。
需要说明的是,这个when里其实是包含两个方面的东西的,一个是模拟对象方法,一个是模拟对象参数,只有两者都同时达到条件时才会返回我们预期的结果
如果需要传入参数,则可以使用Mockito.anyXXX来模拟输入,可以指定一个随便的参数,也可以指定一个指定范围内的参数(anyList),还有集合(anyCollection),任意类(any(Class<T>),比如说要传入一个CustomObj的对象,则使用any(CustomObj)那可返回对应的类对象,这样就可以达到无论什么参数下都会返回预期结果
mock静态需要几个条件:
1. 在class声明@RunWith(PowerMockRunner.class)
2. 在测试方法声明@PrepareForTest({XXX.class})
3. PowerMockito.mockStatic(XXX.class)
4. PowerMockito.when(方法)
测试private方法只限于测试private方法所在类,因为 private不能给其他类引用,所以不需要考虑其他它引用的情况
1. @RunWith(PowerMockRunner.class)
2. 使用 spy Dependency dependency = PowerMockito.spy(new Dependency());
3. 直接修改返回 PowerMockito.doReturn(true).when(dependency, “methodA”, Mockito.anyInt(), Mockito.any(String.class));
验证:PowerMockito.verifyPrivate
关于mock 与 spy
一般的PowerMock.mock创建出来的对象是完全与原对象无关的,其方法,成员都与原类不一致,是一个以类为原点的“修改(mock)”,而spy是以原类的对象实例为基础,访问的时候是以真实的类实例为基础的,是一个以类对象为原点的“修改(mock)”
mockito
mockito的verify里的mock对象可以接受spy对象与mock对象,verify的时候(如方法的调用次数)时只能判断mock对象类型的方法等,如B从A中get来,A会创建B对象,B里有b方法,如果判断b方法有没有执行,不能单纯将从A中GET到的B对象转换为spy对象,否则a去执行b方法时是执行了真正的b方法,mockito根本不知道有没有执行过,因为执行的对象不是mock对象。
统计运行次数
Mockito.never() 从未执行
Mockito.atLeastOne() 至少执行一次
Mockito.atLeast(int) 至少执行n次
Mockito.atMost(int) 至多执行n次
模拟类
用处:
结果,调用次数
androidTest主要是用于测试ui的,需要运行在android环境下,常用的框架Instrumentation、Espresso
场景:
1.A中会创建B对象,B里有b方法,A中有a方法会调用B的b方法,现在想判断B的b有没有执行,执行多少次
需要先在测试方法上声明 @PrepareForTest({A.class,B.class}),然后 对B类的创建一个监控,然后再创建A,A创建B的时候就会返回mock对象。
1 | @Test |
注:反射无效
=====================================
2016.9.19更新
1. 一般来说powermock与robolectric不能共用,硬要共用也可以,不过可能会出各种问题,尽量不要设计这样子的代码
2. powermock的时候mock的最小单位是方法,不能根据方法参数去mock,可以使用Mockito.any(),//但可以自定义Answer
3.1
2
3
4
5
6
7
8
9PowerMockito.when(PersistedObjs.getInstance().getInt(Mockito.any(Context.class), 13)).thenAnswer(new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
for (Object o : args)
System.out.println(o);
return 119474;
}
});
mock的方法中的参数不能一个使用any一个使用具体值,要不两个都具体,要不两个都any
3. 如果测试的代码内有新线程,新线程内的代码不能被mock
mock静态方法
1. PrepareForTest添加被mock类
2. PowerMockito.when(方法).thenReturn
3.
参考:
https://hkliya.gitbooks.io/unit-test-android-with-robolectric/content/4-custom-shadow.html [自定义testRunner,自定义 shadow]