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 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 单元测试框架TestableMock快速入门(三):校验Mock调用 -> 正文阅读

[开发测试]单元测试框架TestableMock快速入门(三):校验Mock调用

目录

一、概述

二、基本校验器

三、基本匹配器

四、空值匹配器

五、字符串匹配器

六、万能匹配器

七、使用示例


一、概述

在测试中,除了需要将某些含有外部依赖的方法替换为Mock,经常还会需要验证该方法被调用时的参数是否符合预期。

TestableMock中提供了校验器(verifier)和匹配器(matcher)来实现这一功能。譬如:

@Test
public test_case() {
    int res = insToTest.methodToTest();
    verify("mockMethod").with(123, "abc");
}

这个用例会检查在执行被测方法methodToTest()时,名称是mockMethod的Mock方法是否有被调用过,且调用时收到的参数值是否为123"abc"(假设被Mock的mockMethod方法有两个参数)。

除了这种简单校验以外,TestableMock当前已经支持了多种校验器,以及能够模糊匹配参数特征的匹配器

二、基本校验器

  • with(Object... args)?→ 验证方法是否被指定参数调用过;
  • withInOrder(Object... args)?→ 如果指定方法被调用了多次,依据实际调用顺序依次匹配;
  • withTimes(int expectedCount)?→ 验证方法是否被调用过指定次数,忽略对调用参数的检查;
  • without(Object... args)?→ 验证方法从未被使用指定参数调用过;
  • times(int count)?→ 连在with()withInOrder()方法之后使用,验证该方法被同样条件的参数调用过了指定次数;

三、基本匹配器

  • any()?→ 匹配任何值,包括Null
  • any(Class<?> clazz)?→ 匹配任何指定类型或子类型的值
  • anyTypeOf(Class<?>... classes)?→ 匹配在列表中的任意一种类型的值
  • anyString()?→ 匹配任何字符串
  • anyNumber()?→ 匹配任何数值(整数或浮点数)
  • anyBoolean()?→ 匹配任何布尔值
  • anyByte()?→ 匹配任何单字节类型的值
  • anyChar()?→ 匹配任何单字符类型的值
  • anyInt()?→ 匹配任何整数类型的值
  • anyLong()?→ 匹配任何长整数类型的值
  • anyFloat()?→ 匹配任何浮点数类型的值
  • anyDouble()?→ 匹配任何双精度浮点数类型的值
  • anyShort()?→ 匹配任何短整数类型的值
  • anyArray()?→ 匹配任何数组
  • anyArrayOf(Class<?> clazz)?→ 匹配任何指定类型的数组
  • anyList()?→ 匹配任何列表
  • anyListOf(Class<?> clazz)?→ 匹配任何指定类型的列表
  • anySet()?→ 匹配任何集合
  • anySetOf(Class<?> clazz)?→ 匹配任何指定类型的集合
  • anyMap()?→ 匹配任何映射
  • anyMapOf(Class<?> keyClass, Class<?> valueClass)?→ 匹配任何指定类型的映射
  • anyCollection()?→ 匹配任何容器
  • anyCollectionOf(Class<?> clazz)?→ 匹配任何指定类型的容器
  • anyIterable()?→ 匹配任何迭代器
  • anyIterableOf(Class<?> clazz)?→ 匹配任何指定类型的迭代器
  • eq(Object obj)?→ 匹配与指定值相等的对象
  • refEq(Object obj)?→ 匹配指定对象(非值相等,而是就是同一个对象)

四、空值匹配器

  • isNull()?→ 匹配Null
  • notNull()?→ 匹配除Null以外的任何值
  • nullable(Class<?> clazz)?→ 匹配空或指定类型的任何值

五、字符串匹配器

  • contains(String substring)?→ 匹配包含特定子串的字符串
  • matches(String regex)?→ 匹配符合指定正则表达式的字符串
  • endsWith(String suffix)?→ 匹配以指定子串结尾的字符串
  • startsWith(String prefix)?→ 匹配以指定子串开头的字符串

六、万能匹配器

  • any(MatchFunction matcher)?→ 匹配符合指定表达式的值

七、使用示例

【a】编写被测试类

package com.wsh.testable.mock.testablemockdemo;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * 演示Mock方法调用校验器
 */
public class DemoMatcher {

    /**
     * Method to be mocked
     */
    private void methodToBeMocked() {
        // pretend to have some code here
    }

    /**
     * Method to be mocked
     */
    private void methodToBeMocked(Object a1, Object a2) {
        // pretend to have some code here
    }

    /**
     * Method to be mocked
     */
    private void methodToBeMocked(Object[] a) {
        // pretend to have some code here
    }

    public void callMethodWithoutArgument() {
        methodToBeMocked();
    }

    public void callMethodWithNumberArguments() {
        // named variable and lambda variable will be recorded as different type
        // should have them both in test case
        List<Float> floatList = new ArrayList<>();
        floatList.add(1.0F);
        floatList.add(2.0F);
        Long[] longArray = new Long[]{1L, 2L};
        methodToBeMocked(1, 2);
        methodToBeMocked(1L, 2.0);
        methodToBeMocked(new ArrayList<Integer>(){{ add(1); }}, new HashSet<Float>(){{ add(1.0F); }});
        methodToBeMocked(1.0, new HashMap<Integer, Float>(2){{ put(1, 1.0F); }});
        methodToBeMocked(floatList, floatList);
        methodToBeMocked(longArray);
        methodToBeMocked(new Double[]{1.0, 2.0});
    }

    public void callMethodWithStringArgument() {
        methodToBeMocked("hello", "world");
        methodToBeMocked("testable", "mock");
        methodToBeMocked(new String[]{"demo"});
    }

    public void callMethodWithObjectArgument() {
        methodToBeMocked(new BlackBox("hello"), new BlackBox("world"));
        methodToBeMocked(new BlackBox("demo"), null);
        methodToBeMocked(null, new BlackBox("demo"));
    }

}

【b】编写测试类

package com.wsh.testable.mock.testablemockdemo;

import com.alibaba.testable.core.annotation.MockMethod;
import com.alibaba.testable.core.error.VerifyFailedError;
import org.junit.jupiter.api.Test;

import static com.alibaba.testable.core.matcher.InvokeMatcher.any;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyArray;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyArrayOf;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyInt;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyList;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyListOf;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyLong;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyMapOf;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyNumber;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anySetOf;
import static com.alibaba.testable.core.matcher.InvokeMatcher.anyString;
import static com.alibaba.testable.core.matcher.InvokeMatcher.contains;
import static com.alibaba.testable.core.matcher.InvokeMatcher.endsWith;
import static com.alibaba.testable.core.matcher.InvokeMatcher.isNull;
import static com.alibaba.testable.core.matcher.InvokeMatcher.matches;
import static com.alibaba.testable.core.matcher.InvokeMatcher.notNull;
import static com.alibaba.testable.core.matcher.InvokeMatcher.nullable;
import static com.alibaba.testable.core.matcher.InvokeMatcher.startsWith;
import static com.alibaba.testable.core.matcher.InvokeVerifier.verify;
import static org.junit.jupiter.api.Assertions.fail;

/**
 * 演示Mock方法调用校验器
 */
class DemoMatcherTest {

    /**
     * 被测试类
     */
    private DemoMatcher demoMatcher = new DemoMatcher();

    /**
     * Mock容器
     */
    public static class Mock {
        /**
         * 未指明targetClass,默认重写第一个参数类型里面,即DemoMatcher的methodToBeMocked()方法
         */
        @MockMethod(targetMethod = "methodToBeMocked")
        private void methodWithoutArgument(DemoMatcher self) {
        }

        /**
         * Mock DemoMatcher被测类的methodToBeMocked(Object a1, Object a2)方法
         */
        @MockMethod(targetMethod = "methodToBeMocked")
        private void methodWithArguments(DemoMatcher self, Object a1, Object a2) {
        }

        /**
         * Mock DemoMatcher被测类的methodToBeMocked(Object[] a)方法
         */
        @MockMethod(targetMethod = "methodToBeMocked")
        private void methodWithArrayArgument(DemoMatcher self, Object[] a) {
        }
    }

    /**
     * 1. withTimes(int expectedCount) → 验证方法是否被调用过指定次数,忽略对调用参数的检查
     */
    @Test
    void should_match_no_argument() {
        //callMethodWithoutArgument()方法内部调用了methodToBeMocked()方法
        demoMatcher.callMethodWithoutArgument();
        //检查在执行被测方法callMethodWithoutArgument()时,名称是methodWithoutArgument的Mock方法是否有被调用过一次,并忽略对调用参数的检查
        verify("methodWithoutArgument").withTimes(1);
        demoMatcher.callMethodWithoutArgument();
        //检查在执行被测方法callMethodWithoutArgument()时,名称是methodWithoutArgument的Mock方法是否有被调用过两次,并忽略对调用参数的检查
        verify("methodWithoutArgument").withTimes(2);
    }

    /**
     * 2.with(Object... args) → 验证方法是否被指定参数调用过
     * withInOrder(Object... args) → 如果指定方法被调用了多次,依据实际调用顺序依次匹配
     * without(Object... args) → 验证方法从未被使用指定参数调用过
     */
    @Test
    void should_match_number_arguments() {
        //callMethodWithNumberArguments()方法内部调用了methodToBeMocked()很多重载的方法
        demoMatcher.callMethodWithNumberArguments();
        //验证Mock方法methodWithArguments()从未被使用指定参数调用过
        verify("methodWithArguments").without(anyString(), 2);
        //withInOrder(Object... args) → 如果指定方法被调用了多次,依据实际调用顺序依次匹配
        verify("methodWithArguments").withInOrder(anyInt(), 2);
        verify("methodWithArguments").withInOrder(anyLong(), anyNumber());

        //验证Mock方法methodWithArguments()是否被指定参数调用过
        verify("methodWithArguments").with(1.0, anyMapOf(Integer.class, Float.class));
        verify("methodWithArguments").with(anyList(), anySetOf(Float.class));
        verify("methodWithArguments").with(anyList(), anyListOf(Float.class));

        //验证Mock方法methodWithArrayArgument()是否被指定参数调用过
        verify("methodWithArrayArgument").with(anyArrayOf(Long.class));
        verify("methodWithArrayArgument").with(anyArray());
    }

    /**
     * 3.
     * contains(String substring) → 匹配包含特定子串的字符串
     * matches(String regex) → 匹配符合指定正则表达式的字符串
     * endsWith(String suffix) → 匹配以指定子串结尾的字符串
     * startsWith(String prefix) → 匹配以指定子串开头的字符串
     */
    @Test
    void should_match_string_arguments() {
        //注意callMethodWithStringArgument()在类DemoMatcher中的实现
        demoMatcher.callMethodWithStringArgument();
        //验证Mock方法methodWithArguments()是否被指定参数调用过,参数分别满足以"he"开头、以"ld"结尾
        verify("methodWithArguments").with(startsWith("he"), endsWith("ld"));
        //参数类型:包含"stab"、匹配"m.[cd]k"正则表达式
        verify("methodWithArguments").with(contains("stab"), matches("m.[cd]k"));
        //参数类型:String类型的数组
        verify("methodWithArrayArgument").with(anyArrayOf(String.class));
    }


    /**
     * 4.
     * withInOrder(Object... args) → 如果指定方法被调用了多次,依据实际调用顺序依次匹配
     */
    @Test
    void should_match_object_arguments() {
        demoMatcher.callMethodWithObjectArgument();
        verify("methodWithArguments").withInOrder(any(BlackBox.class), any(BlackBox.class));
        verify("methodWithArguments").withInOrder(nullable(BlackBox.class), nullable(BlackBox.class));
        verify("methodWithArguments").withInOrder(isNull(), notNull());
    }

    /**
     * 5.
     * times(int count) → 连在with()或withInOrder()方法之后使用,验证该方法被同样条件的参数调用过了指定次数
     */
    @Test
    void should_match_with_times() {
        demoMatcher.callMethodWithNumberArguments();
        verify("methodWithArguments").with(anyNumber(), any()).times(3);

        demoMatcher.callMethodWithNumberArguments();
        boolean gotError = false;
        try {
            verify("methodWithArguments").with(anyNumber(), any()).times(4);
        } catch (VerifyFailedError e) {
            gotError = true;
        }
        if (!gotError) {
            fail();
        }
    }

}

本案例来自官网, 笔者只是做一个学习总结。更详细使用介绍参考官网:TestableMock

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-09-23 11:45:14  更:2021-09-23 11:45:18 
 
开发: 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/18 0:22:10-

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