栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

关于 Mockito BDDMockito

Java 更新时间:发布时间: 百科书网 趣学号

关于 Mockito BDDMockito
  • 前言
  • Mockito BDDMockito
    • mock
    • stub
    • matcher
    • inorder
    • consecutive
    • answer
    • spy
    • oneLinerStubs
  • 总结

前言

向很多开源社区提交代码是需要做完整的 单元测试 的,其中 mock 目标实例、给 mock 对象打桩 等操作可以极大提高测试代码的效率和可读性

本章节基于 Mockito BDDMockito 的 API DEMO 熟悉一些基本操作,Spring Test 包含对应依赖

Mockito BDDMockito

其中 BDD 代表 behavior driven deployment,我理解就是让测试代码语义更接近现实行为,比如

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

        List mock = mock(List.class);

        mock.add("test");
        mock.add("test1");
        mock.add("test1");
        mock.get(0);

        // verify:是否调用目标方法
        verify(mock).add("test");
        // BDD style
        then(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");

        // error
        verify(mock).add("test2");
        verify(mock).get(1);
    }
  • mock 方法创建 mock 对象,即一个临时虚拟对象,测试基于该示例进行
  • verify 是 Mockito 下的 API,类似于断言,比如 verify(mock).add("test") 就是检验该方法是否调用
  • then 是 BDDMockito 的 API,类比于 verify 更加语义化
stub
	@Test
    public void stubDemo() {

        ArrayList mock = mock(ArrayList.class);

        // 打桩
        when(mock.get(0)).thenReturn("a");
        // BDD-style
        given(mock.get(0)).willReturn("a");

        when(mock.get(1)).thenThrow(new RuntimeException("test"));
        // given(mock.get(1)).willThrow(new RuntimeException("test"));

        doThrow(new RuntimeException("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 API 是 when ... then ...
  • 对应的 BDDMockito 是 then ... will ...
matcher
	@Test
    public void matcherDemo() {

        ArrayList mock = mock(ArrayList.class);

        // 匹配任意 int
        when(mock.get(anyInt())).thenReturn("meta");
        given(mock.get(anyInt())).willReturn("meta");

        // 所有的方法都要使用 matcher
        when(mock.subList(anyInt(), eq(1))).thenReturn(new ArrayList() {{
            add("meta2");
        }});
        given(mock.subList(anyInt(), eq(1))).willReturn(new ArrayList() {{
            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
	@Test
    public void orderDemo() {

        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-style
        then(mock2).should(inOrder).add(2);

        // error
        inOrder.verify(mock).add(1);
    }
  • 这段代码可以测试 mock 实例的方法执行顺序是否符合预期
  • 可以多个实例、多个方法结合使用,可看 demo 理解
  • 顺序前后符合即可,可以不严格,即 1 2 3 4 可以是 1 2 4、1 3 4 但不可以 2 1 3 4
consecutive
	@Test
    public void consecutiveDemo() {
        ArrayList mock = mock(ArrayList.class);

        when(mock.get(anyInt()))
                .thenReturn(0, 1, 2);

        // 0
        System.out.println(mock.get(0));
        // 1
        System.out.println(mock.get(1));
        // 2
        System.out.println(mock.get(2));
        // 2
        System.out.println(mock.get(3));

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

        when(mock.get(anyInt()))
                .then(invocation -> {
                    Object argument = invocation.getArgument(0);
                    return argument + "r";
                });
        // BDD-style
        given(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
	@Test
    public void spyDemo() {
        List list = new LinkedList();
        List spy = spy(list);

        spy.add(1);

        when(spy.size()).thenReturn(10);
        // BDD-style
        given(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
	@Test
    public void oneLinerStubsDemo() {
        HelloService helloService = when(mock(HelloService.class).hello())
                .thenReturn("hello world")
                .getMock();
        // BDD-style
        HelloService 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

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/867962.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号