zoukankan      html  css  js  c++  java
  • 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());

           }

    生命很短,请让生活更精彩一些!
  • 相关阅读:
    面试官:HashMap死循环形成的原因是什么?
    这几个IDEA高级调试技巧,用完就是香
    图示JVM工作原理
    写二进制,姿势一定要骚,省字段,省带宽,提效率...
    阿里大佬总结的40个多线程面试题,你能答上来几个?
    全网最全RabbitMQ总结,别再说你不会RabbitMQ
    .NETCore微服务探寻(三)
    .NETCore微服务探寻(二)
    .NETCore微服务探寻(一)
    谈谈spring-boot-starter-data-redis序列化
  • 原文地址:https://www.cnblogs.com/Aaron-007/p/10441506.html
Copyright © 2011-2022 走看看