android使用mockito进行单元测试

Author Avatar
weechan 3月 25, 2018

Android单元测试

标签(空格分隔): 单元测试


Mockito的使用(kotlin坑多建议勿用)

导入Mockito的依赖
testCompile ‘org.mockito:mockito-core:2.7.6’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Mock
private List<String> data = new ArrayList<>();

@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
//初始化Mock注解生成的对象,比如Mock对象,ArgumentCaptor等
List<String> datas = Mockito.mock(List.class);
//创建Mock对象,与 @Mock 注解同理
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
//创建ArugmentCaptor 与@Captor注解同理
//后面会讲解ArgumentCaptor

}

验证调用,次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void TestStudy(){

datas.add("AAA");
datas.add("BBB");
datas.clear();

verify(datas).clear();

// any 有很多方法 可以匹配任意参数 比如 anyInt()
verify(datas,times(2)).add(anyString());
//调用两次
verify(datas,never()).addAll(any(Collection.class));
//从不调用
verify(datas,atLeast(2)).add(anyString());
//至少调用2次
verify(datas,atMost(2)).add(anyString());
//至多调用3次
}

修改行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    @Test
public void testReturn(){

when(datas.get(anyInt())).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Integer index = invocation.getArgument(0);
return "YOUR INDEX IS : NO." + index;
}
});
//获取方法的参数并返回参数组成的字符串

when(datas.get(255))
.thenReturn("FIRST INVOKE GET(255)")
.thenReturn("SECOND INVOKE GET(255)")
.thenThrow(new RuntimeException("CAN'T GET MORE THAN THREE TIMES"));
//第一次返回第一句thenReturn,第二次第二句,第三次抛异常

doThrow(new RuntimeException()).when(datas).clear();
//清空数据则抛异常

System.out.println(datas.get(25));
System.out.println(datas.get(255));
System.out.println(datas.get(255));
System.out.println(datas.get(15));

// datas.clear(); 执行则会出错
// System.out.println(datas.get(255)); 执行则会出错

output:
YOUR INDEX IS : NO.25
FIRST INVOKE GET(255)
SECOND INVOKE GET(255)
YOUR INDEX IS : NO.1
}

```

#### 参数匹配
@Test
public void testMatcher(){
    //匹配包含HTTP的字符串
    class HTTPStringmatcher implements ArgumentMatcher<String> {
        @Override
        public boolean matches(String argument) {
            return argument.contains("HTTP");
        }
    }
    //当包含的参数有HTTP 则返回true
    when(datas.contains(argThat(new HTTPStringmatcher()))).thenReturn(true);

    //有时候 使用thenAnswer 比 Matcher 更加灵活

    System.out.println(datas.contains("NOT CONTAINS"));
    System.out.println(datas.contains("CONTAINS HTTP"));

     output
       false
       true


}
1
2

#### 参数捕捉
@Test
public void testCaptor(){

    datas.add("ADD ONE STRING");
    datas.add("ADD TWO STRING");

    //验证时对方法的参数进行捕获
    verify(datas,times(2)).add(stringCaptor.capture());
    System.out.println(stringCaptor.getAllValues());
    //  output : [ADD ONE STRING, ADD TWO STRING]
}
1
2

#### 验证顺序
@Test
public void testOrder(){
    datas.add("A");
    datas.clear();
    datas.add("B");
    InOrder order =  inOrder(datas);
    //顺序以及参数要完全匹配
    order.verify(datas).add("A");
    order.verify(datas).clear();
    order.verify(datas).add("B");
}
1
2

#### 未验证互动
@Test
public void redundant(){
    datas.add("ONE");
    datas.add("TWO");
    verify(datas,times(2)).add(anyString());
    verifyNoMoreInteractions(datas);
    //检查未验证的互动
    //上面的例子 验证通过

// datas.add(“C”);
// verifyNoMoreInteractions(datas);
// 加上上面两行则不通过,因为add(“C”)未被verify

}
1
2

#### 零互动
@Test
    public void verifyZero(){
        List a = mock(List.class);
        List b = mock(List.class);
        List c = mock(List.class);

        a.add(1);
        //验证对象都没有互动产生
        verifyZeroInteractions(a,b,c);
        //上述代码异常,因为list a 进行了操作,

    }
1
2

#### 清除mock
@Test
public void reset_mock(){
    List list = mock(List.class);
    when(list.size()).thenReturn(10);
    list.add(1);
    assertEquals(10,list.size());
    //重置mock,清除所有的互动和预设
    reset(list);
    assertEquals(0,list.size());
}

Spy

1
2

#### 监控真实对象Spy
@Test
public void spyTest() {

    List<String> list = new ArrayList<>();
    List spy = spy(list);
    //spy会调用真实对象的方法
    doReturn("HELLO SPYER").when(spy).get(100);
    //do...when 会避免调用真实对象的方法
    when(spy.get(50)).thenReturn("OUT OF BOUNDS");
    //when...then 会调用真实对象方法, 因为此时length为0 调用get(50)会异常
    assertEquals(spy.get(100),"HELLO SPYER");
    assertEquals(spy.get(50),"OUT OF BOUNDS");

}

`

利用mockito测试Presenter
在下篇文章讲述