人生三大境界
衣带渐宽终不悔,为伊消得人憔悴。
昨夜西风凋碧树,独上高楼,望尽天涯路。
众里寻他千百度,蓦然回首,那人却在灯火阑珊处。

Mockito框架入门教程(二)

接上一篇,继续学习其它的....

8、找出冗余的互动(即未被验证到的)

       @Test(expected = NoInteractionsWanted.class)

       public void find_redundant_interaction(){

              List list = mock(List.class);

              list.add(1);

              list.add(2);

              verify(list,times(2)).add(anyInt());

              //检查是否有未被验证的互动行为,因为add(1)和add(2)都会被上面的anyInt()验证到,所以下面的代码会通过

              verifyNoMoreInteractions(list);

 

              List list2 = mock(List.class);

              list2.add(1);

              list2.add(2);

              verify(list2).add(1);

              //检查是否有未被验证的互动行为,因为add(2)没有被验证,所以下面的代码会失败抛出异常

              verifyNoMoreInteractions(list2);

       }

9、使用注解来快速模拟

在上面的测试中我们在每个测试方法里都mock了一个List对象,为了避免重复的mock,使测试类更具有可读性,我们可以使用下面的注解方式来快速模拟对象:

 

       @Mock

       private List mockList;

OK,我们再用注解的mock对象试试

       @Test

       public void shorthand(){

              mockList.add(1);

              verify(mockList).add(1);

       }

运行这个测试类你会发现报错了,mock的对象为NULL,为此我们必须在基类中添加初始化mock的代码

public class MockitoExample2 {

       @Mock

       private List mockList;

 

       public MockitoExample2(){

              MockitoAnnotations.initMocks(this);

       }

 

       @Test

       public void shorthand(){

              mockList.add(1);

              verify(mockList).add(1);

       }

}

或者使用built-in runner:MockitoJUnitRunner

 

 

@RunWith(MockitoJUnitRunner.class)

public class MockitoExample2 {

       @Mock

       private List mockList;

 

       @Test

       public void shorthand(){

              mockList.add(1);

              verify(mockList).add(1);

       }

}

更多的注解还有@Captor,@Spy,@InjectMocks

 

10、连续调用

       @Test(expected = RuntimeException.class)

       public void consecutive_calls(){

              //模拟连续调用返回期望值,如果分开,则只有最后一个有效

              when(mockList.get(0)).thenReturn(0);

              when(mockList.get(0)).thenReturn(1);

              when(mockList.get(0)).thenReturn(2);

              when(mockList.get(1)).thenReturn(0).thenReturn(1).thenThrow(new RuntimeException());

              assertEquals(2,mockList.get(0));

              assertEquals(2,mockList.get(0));

              assertEquals(0,mockList.get(1));

              assertEquals(1,mockList.get(1));

              //第三次或更多调用都会抛出异常

              mockList.get(1);

       }

11、使用回调生成期望值

       @Test

       public void answer_with_callback(){

              //使用Answer来生成我们我们期望的返回

              when(mockList.get(anyInt())).thenAnswer(new Answer<Object>() {

                     @Override

                     public Object answer(InvocationOnMock invocation) throws Throwable {

                            Object[] args = invocation.getArguments();

                            return "hello world:"+args[0];

                     }

              });

              assertEquals("hello world:0",mockList.get(0));

              assertEquals("hello world:999",mockList.get(999));

       }

12、监控真实对象

使用spy来监控真实的对象,需要注意的是此时我们需要谨慎的使用when-then语句,而改用do-when语句

 

 

       @Test(expected = IndexOutOfBoundsException.class)

       public void spy_on_real_objects(){

              List list = new LinkedList();

              List spy = spy(list);

              //下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常

              //when(spy.get(0)).thenReturn(3);

 

              //使用doReturn-when可以避免when-thenReturn调用真实对象api

              doReturn(999).when(spy).get(999);

              //预设size()期望值

              when(spy.size()).thenReturn(100);

              //调用真实对象的api

              spy.add(1);

              spy.add(2);

              assertEquals(100,spy.size());

              assertEquals(1,spy.get(0));

              assertEquals(2,spy.get(1));

              verify(spy).add(1);

              verify(spy).add(2);

              assertEquals(999,spy.get(999));

              spy.get(2);

       }

13、修改对未预设的调用返回默认期望值

 

       @Test

       public void unstubbed_invocations(){

              //mock对象使用Answer来对未预设的调用返回默认期望值

              List mock = mock(List.class,new Answer() {

                     @Override

                     public Object answer(InvocationOnMock invocation) throws Throwable {

                            return 999;

                     }

              });

              //下面的get(1)没有预设,通常情况下会返回NULL,但是使用了Answer改变了默认期望值

              assertEquals(999, mock.get(1));

              //下面的size()没有预设,通常情况下会返回0,但是使用了Answer改变了默认期望值

              assertEquals(999,mock.size());

       }

14、捕获参数来进一步断言

 

    @Test

       public void capturing_args(){

              PersonDao personDao = mock(PersonDao.class);

              PersonService personService = new PersonService(personDao);

 

              ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);

              personService.update(1,"jack");

              verify(personDao).update(argument.capture());

              assertEquals(1,argument.getValue().getId());

              assertEquals("jack",argument.getValue().getName());

       }

 

        class Person{

              private int id;

              private String name;

 

              Person(int id, String name) {

                     this.id = id;

                     this.name = name;

              }

 

              public int getId() {

                     return id;

              }

 

              public String getName() {

                     return name;

              }

       }

 

       interface PersonDao{

              public void update(Person person);

       }

 

       class PersonService{

              private PersonDao personDao;

 

              PersonService(PersonDao personDao) {

                     this.personDao = personDao;

              }

 

              public void update(int id,String name){

                     personDao.update(new Person(id,name));

              }

       }

15、真实的部分mock

 

       @Test

       public void real_partial_mock(){

              //通过spy来调用真实的api

              List list = spy(new ArrayList());

              assertEquals(0,list.size());

              A a  = mock(A.class);

              //通过thenCallRealMethod来调用真实的api

              when(a.doSomething(anyInt())).thenCallRealMethod();

              assertEquals(999,a.doSomething(999));

       }

 

 

       class A{

              public int doSomething(int i){

                     return i;

              }

       }

16、重置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());

       }

posted @ 2019-02-27 09:26  一剑霜寒十九洲  阅读(370)  评论(0编辑  收藏  举报