IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 关于 Mockito BDDMockito -> 正文阅读

[开发测试]关于 Mockito BDDMockito

前言

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

本章节基于 Mockito BDDMockitoAPI 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 对象,即一个临时虚拟对象,测试基于该示例进行
  • verifyMockito 下的 API,类似于断言,比如 verify(mock).add("test") 就是检验该方法是否调用
  • thenBDDMockitoAPI,类比于 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 APIwhen ... then ...
  • 对应的 BDDMockitothen ... 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 41 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 实例在自然语义 givenwhen 阶段下的所有行为

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 BDDMockitoDEMO,旨在写出实用又好看的 单元测试

完整示例 demo

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 12:13:06  更:2022-05-10 12:13:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 22:30:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码