0


关于 Mockito BDDMockito

关于 Mockito BDDMockito

前言

向很多开源社区提交代码是需要做完整的

单元测试

的,其中

mock

目标实例、给

mock

对象打桩 等操作可以极大提高测试代码的效率和可读性

本章节基于

Mockito
BDDMockito

API
DEMO

熟悉一些基本操作,

Spring Test

包含对应依赖

Mockito BDDMockito

其中

BDD

代表

behavior driven deployment

,我理解就是让测试代码语义更接近现实行为,比如

  • given 就是 给定 ... 条件下,可以类比为 打桩(当然也可以不打)
  • when 就是 发生 ... 行为,比如 mock 实例的方法调用(当然也可以不发生)
  • then,就是 则 ...打桩mock 实例执行目标方法后的校验
语义化的东西强行解释总感觉生硬

mock

@TestpublicvoidmockDemo(){List mock =mock(List.class);

        mock.add("test");
        mock.add("test1");
        mock.add("test1");
        mock.get(0);// verify:是否调用目标方法verify(mock).add("test");// BDD stylethen(mock).should().add("test");// 目标方法调用一次verify(mock,times(1)).add("test");then(mock).should(times(1)).add("test");// 目标方法至少调用 2 次verify(mock,atLeast(2)).add("test1");then(mock).should(atLeast(2)).add("test1");// 目标方法最多调用 2 次verify(mock,atMost(2)).add("test1");then(mock).should(atMost(2)).add("test1");// 目标方法未调用verify(mock,never()).add("test2");then(mock).should(never()).add("test2");// errorverify(mock).add("test2");verify(mock).get(1);}
  • mock 方法创建 mock 对象,即一个临时虚拟对象,测试基于该示例进行
  • verifyMockito 下的 API,类似于断言,比如 verify(mock).add("test") 就是检验该方法是否调用
  • thenBDDMockitoAPI,类比于 verify 更加语义化

stub

@TestpublicvoidstubDemo(){ArrayList mock =mock(ArrayList.class);// 打桩when(mock.get(0)).thenReturn("a");// BDD-stylegiven(mock.get(0)).willReturn("a");when(mock.get(1)).thenThrow(newRuntimeException("test"));// given(mock.get(1)).willThrow(new RuntimeException("test"));doThrow(newRuntimeException("void")).when(mock).clear();// willThrow(new RuntimeException("void")).given(mock).clear();System.out.println(mock.get(0));try{
            mock.get(1);}catch(Exception e){System.out.println(e.getMessage());}System.out.println(mock.get(2));}
  • 这是一段 stub 代码,即打桩操作,主要应付方法逻辑复杂且非测试目标的场景
  • 对应的 Mockito``````APIwhen ... then ...
  • 对应的 BDDMockitothen ... will ...

matcher

@TestpublicvoidmatcherDemo(){ArrayList mock =mock(ArrayList.class);// 匹配任意 intwhen(mock.get(anyInt())).thenReturn("meta");given(mock.get(anyInt())).willReturn("meta");// 所有的方法都要使用 matcherwhen(mock.subList(anyInt(),eq(1))).thenReturn(newArrayList(){{add("meta2");}});given(mock.subList(anyInt(),eq(1))).willReturn(newArrayList(){{add("meta2");}});System.out.println(mock.get(12));System.out.println(mock.subList(3,1));// then 阶段也可以使用verify(mock).get(anyInt());then(mock).should().get(anyInt());}
  • 可以对参数进行匹配,比如 anyInt() 匹配任意 Integer
  • 这个针对 Mockito``````BDDMockito 都一样
  • 自然语义下的 then 阶段也可以使用 matcher 来匹配
我指的自然语义就是 given ... when ... then ...

inorder

@TestpublicvoidorderDemo(){ArrayList mock =mock(ArrayList.class);LinkedList mock2 =mock(LinkedList.class);

        mock.add(1);
        mock.add(2);
        mock2.add(1);
        mock2.add(2);// 可以有多个实例InOrder inOrder =inOrder(mock, mock2);

        inOrder.verify(mock).add(1);
        inOrder.verify(mock).add(2);// correct,可以跳过// inOrder.verify(mock2).add(2);
        inOrder.verify(mock2).add(1);// BDD-stylethen(mock2).should(inOrder).add(2);// error
        inOrder.verify(mock).add(1);}
  • 这段代码可以测试 mock 实例的方法执行顺序是否符合预期
  • 可以多个实例、多个方法结合使用,可看 demo 理解
  • 顺序前后符合即可,可以不严格,即 1 2 3 4 可以是 1 2 41 3 4 但不可以 2 1 3 4

consecutive

@TestpublicvoidconsecutiveDemo(){ArrayList mock =mock(ArrayList.class);when(mock.get(anyInt())).thenReturn(0,1,2);// 0System.out.println(mock.get(0));// 1System.out.println(mock.get(1));// 2System.out.println(mock.get(2));// 2System.out.println(mock.get(3));// 清空reset(mock);System.out.println(mock.get(0));}
  • 打桩 的结果可以指定多个,会依此返回
  • 如果没有其他结果,则保持最后一个
  • reset 可情况 mock 实例在自然语义 givenwhen 阶段下的所有行为

answer

@TestpublicvoidanswerDemo(){ArrayList mock =mock(ArrayList.class);when(mock.get(anyInt())).then(invocation ->{Object argument = invocation.getArgument(0);return argument +"r";});// BDD-stylegiven(mock.get(anyInt())).will(invocationOnMock ->{Object argument = invocationOnMock.getArgument(0);return argument +"r";});System.out.println(mock.get(0));System.out.println(mock.get(1));}
  • 打桩 结果指定更加灵活的 Answer
  • 示例中是基于 lambda 风格的实现

spy

@TestpublicvoidspyDemo(){List list =newLinkedList();List spy =spy(list);

        spy.add(1);when(spy.size()).thenReturn(10);// BDD-stylegiven(spy.size()).willReturn(10);System.out.println(spy.get(0));System.out.println(spy.size());// spy 只是一个 copy,所以 list 上的操作不影响 spy
        list.add(2);
        spy.forEach(System.out::println);}
  • spy 方法可返回一个 spy 实例,该实例除了 打桩 行为外的调用都与原实例相同,比如示例中 spy.add(1) 方法就是正常的 ArrayList::add,而 spy.size() 因为被 stub 只返回 10
  • 值得注意的是,原对象上的操作并不影响 spy 示例,比如示例中 list.add(2) 并不意味着 spy.get(1) == 2

oneLinerStubs

@TestpublicvoidoneLinerStubsDemo(){HelloService helloService =when(mock(HelloService.class).hello()).thenReturn("hello world").getMock();// BDD-styleHelloService helloService2 =given(mock(HelloService.class).hello()).willReturn("hello world 2").getMock();System.out.println(helloService.hello());System.out.println(helloService2.hello());}
  • 一行式 demo
  • getMock 方法返回 mock 实例

总结

本文介绍一些基于

Mockito
BDDMockito

DEMO

,旨在写出实用又好看的

单元测试

完整示例 demo

标签: java 单元测试

本文转载自: https://blog.csdn.net/weixin_42189048/article/details/124648470
版权归原作者 小水牛... 所有, 如有侵权,请联系我们删除。

“关于 Mockito BDDMockito”的评论:

还没有评论