Android 单元测试之JUnit和Mockito
Android 单元测试之JUnit和Mockito
Android 单元测试之JUnit和Mockito
Android 单元测试之Roboletric 环境配置
Android 单元测试之Roboletric的简单使用
Android 单元测试之Roboletric RxJava、Retrofit、访问真实网络、虚拟服务器
Android 单元测试之Espresso - Google官方UI测试框架
JUnit
使用JUnit测试框架需要引入依赖,在新建项目的时候,Android Studio已自动帮我们引入了该依赖
dependencies { ... testCompile 'junit:junit:4.12' }
注解说明
JUnit提供了一些注解帮助我们更好的完成测试
@Before该方法在每次测试方法调用前都会调用@Test说明了该方法需要测试@BeforeClass该方法在所有测试方法之前调用,只会被调用一次@After该方法在每次测试方法调用后都会调用@AfterClass该方法在所有测试方法之后调用,只会被调用一次@Ignore忽略该方法
假如我们已经写好了多个测试用例,每次只需要测试其中的三四个,而不需要把所有的测试用例都跑一遍,这该怎么办呢?
不用担心,JUnit已经为我们提供了方法。假设有三个写好的测试用例,我们只需要调用其中的两个,就可以这么做:
@Suite.SuiteClasses({FirstTest.class,ThirdTest.class})public class SpecializeTests{}
Mockito
mock对象就是在调试期间用来作为真实对象的替代品。Mockito是Java中常见的Mock框架。
添加依赖
dependencies { ... testCompile 'org.mockito:mockito-all:2.0.2-beta'}
创建Mock对象
List mockedList = mock(List.class);
可用@Mock注解创建,比较简单
@MockList mockedList; @Testpublic void testMock(){ //初始化@Mock注解的对象 (进行注入) MockitoAnnotations.initMocks(this);}
使用@Mock注解需要使用MockitoAnnotations.initMocks(this);进行注入
验证某些行为
Mock对象将记住所有的操作,可以验证其行为
//使用Mock对象mockedList.add("one");mockedList.clear();//验证函数的调用次数verify(mockedList).add("one");//verify(mockedList).add("two"); 无此操作,验证 failedverify(mockedList).clear();
做一些桩测试
在创建出Mock对象后,默认返回值为null,故可做进行打桩,每当调用该打桩后的方法或变量后,让其返回相应的值。
//测试桩,在调用get(0)时返回"first"when(mockedList.get(0)).thenReturn("first");//调用get(1)时抛出异常when(mockedList.get(1)).thenThrow(new RuntimeException());//输出firstSystem.out.println(mockedList.get(0));//抛出异常//System.out.println(mockedList.get(1));//因为get(999)没有打桩,因此输出nullSystem.out.println(mockedList.get(999));
参数匹配器
让打桩更具灵活性,比如anyInt()将匹配所有的int值
//使用内置的anyInt()参数匹配器,当调用get(int)时都返回"element"when(mockedList.get(anyInt())).thenReturn("element");//使用自定义的参数器(在inValid()函数中返回你自己的匹配器实现)//when(mockedList.get(isValid())).thenReturn("element");//输出elementSystem.out.println(mockedList.get(999));//也可以验证匹配器//verify(mockedList).get(anyInt());
验证函数的确切调用次数、最少调用、从未调用
mockedList.add("once");mockedList.add("twice");mockedList.add("twice");mockedList.add("three times");mockedList.add("three times");mockedList.add("three times");//下面两个的验证结果一样,因为verify默认验证的就是times(1)verify(mockedList).add("once");verify(mockedList, times(1)).add("once");//验证具体的执行次数verify(mockedList, times(2)).add("twice");verify(mockedList, times(3)).add("three times");//使用never验证,never相当于time(0)verify(mockedList, never()).add("never happened");//使用atLeast()/atMostverify(mockedList, atLeastOnce()).add("three times");verify(mockedList, atLeast(2)).add("twice");verify(mockedList, atMost(5)).add("three times");List mockTwo = mock(List.class); //验证Mock对象没有交互过//verifyZeroInteractions(mockedList); //mockedList已交互过verifyZeroInteractions(mockTwo); //mockTwo没有交互过
为连续的调用做测试桩(Stub)
打桩根据调用顺序返回不同的值
/*when(mockedList.get(anyInt())) .thenThrow(new RuntimeException()) .thenReturn("foo");*//*//第一次调用:抛出运行时异常System.out.println(mockedList.get(0));//第二次调用:输出"foo"System.out.println(mockedList.get(1));//第三次调用:也是输出"foo"System.out.println(mockedList.get(2));*///另外,连续调用的另一种更简短的方式when(mockedList.get(anyInt())) .thenReturn("one", "two", "three");
为回调做测试桩
when(mockedList.get(anyInt())).thenAnswer(new Answer() { @Override public String answer(InvocationOnMock invocation) throws Throwable { //获取函数调用的参数 Object[] args = invocation.getArguments(); //获得Mock对象本身 Object mock = invocation.getMock(); return "answer===>" + mock.toString(); }});System.out.println(mockedList.get(50));//doReturn(),doThrow(),doAnswer(),doNothing(),noCallRealMethod()
Spy
Spy可用来处理遗留代码
//spy应尽量少用,可用来处理遗留代码 (没有使用mock生成的对象)List list = new LinkedList();//监控一个真实的对象List spy = spy(list);//可以为某些函数打桩when(spy.size()).thenReturn(100);//在监控真实对象上使用when会报错,可以使用onReturn、Answer、Throw()函数族来进行打桩//不能:因为当调用spy.get(0)时会调用真实对象的get(0)函数,此时会发生IndexOutOfBoundsException异常,因为真实List对象是空的//when(spy.get(0)).thenReturn("foo");doReturn("foo").when(spy).get(0);System.out.println(spy.get(0));//Mockito并不会为真实对象代理函数(Method)调用,实际上它会复制真实对象。//当你在监控一个真实对象时,你想为这个真实对象的函数做测试桩,那么就是在自找麻烦。//通过spy对象调用真实对象的函数spy.add("one");spy.add("two");System.out.println(spy.get(0));System.out.println(spy.size());//交互验证verify(spy).add("one");verify(spy).add("two");
为下一步的断言捕获参数
ArgumentCaptor与自定义的参数匹配器相关
这两种技术都能用于检测外出传递到Mock对象的参数
rgumentCaptor更适合以下情况:1.自定义不能被重用的参数匹配器
2.仅需要断言参数值
//在某些场景中,不光要对方法的返回值和调用进行验证,同时需要验证一系列交互后所传入方法的参数。那么我们可以用参数捕获器来捕获传入方法的参数进行验证,看它是否符合我们的要求。mockedList.add("Haha");ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);verify(mockedList).add(argument.capture());assertEquals("Haha", argument.getValue());
ArgumentCaptor详情介绍
其他
参考 《Android开发进阶 从小工到专家》
相关源码
更多相关文章
- Android修改自己程序字体的方法详解
- android使用android:ellipsize="end"无效的解决方法
- Android 软件安装方法介绍
- Android单元测试初探Instrumentation
- Android实现全屏显示的方法
- Android渗透测试Android渗透测试入门教程大学霸
- Android单元测试