title author date CreateTime categories
dotnet 如何在 Mock 模拟 Func 判断调用次数
lindexi
2019-08-31 16:55:58 +0800
2019-5-28 15:3:36 +0800
dotnet

在 dotnet 程序有很好用的 Mock 框架,可以用来模拟各种接口和抽象类,可以用来测试某个注入接口的被调用次数和被调用时传入参数。本文告诉大家如何在 Mock 里面模拟一个 Func 同时模拟返回对象,获取调用次数

在 Mock 里面可以通过 Mock<Func<string>> 创建一个返回字符串的委托,通过 Setup 设置调试参数过滤和对应的模拟的返回值。如我期望模拟一个 Func 是 Func<int, string> 同时有要求传入的参数的值和想要在用户传入参数 0 的时候模拟返回值是 林德熙是逗比 如果用户传入的是其他的值,那么就不在意了

在 Mock 里面通过 Setup 可以说明如何进行模拟,写法是 Setup 里面调用的方法里面传入的参数就是说明当用户也传入什么参数的时候,在 Setup 返回值里面添加 Returns 方法说明如何返回

    mock.Setup(对象 => 对象.Xx方法(模拟用户传入的是什么参数)).Returns(模拟返回值);

如上面的需求可以这样写,在 Setup 里面调用 Func 传入参数 0 表示当用户传入参数 0 的时候执行什么,在后面的 Returns 方法是模拟返回值

 mock.Setup(func => func(0)).Returns("林德熙是逗比");

判断用户调用了模拟的方法多少次通过 Verify 方法,在 Verify 方法是调用模拟的方法,在模拟的方法传入参数指定在传入对应参数的时候,此方法调用了多少次

 mock.Verify(func => 对象.Xx方法(模拟用户传入的是什么参数), Times.Xx在传入什么参数的时候被调用了多少次);

例如当用户传入参数 0 的时候被调用一次可以这样写

 mock.Verify(func => func(0), Times.Once);

现在尝试写一个单元测试跑一下

        [ContractTestCase]
public void FooTests()
{
"当调用 Foo 时,将会传入 0 和 1 分别运行一次".Test(() =>
{
// Arrange
var mock = new Mock<Func<int, string>>();
mock.Setup(func => func(0)).Returns("林德熙是逗比"); // Action
Foo(mock.Object); // Assert
mock.Verify(func => func(1), Times.Once);
mock.Verify(func => func(0), Times.Once);
});
}

这个方式的单元测试是 MSTestEnhancer 提供的写法,可以将会写单元测试的理解和维护成本。传统的单元测试是要求命名的时候安装英文的规范命名,但是我的团队的小伙伴的英文都太渣了,要么就是太好了,反正我自己写的单元测试的方法命名我自己都看不懂。然而加上了 Display 特性用来显示中文的时候,依然存在的问题是需要自己想很久命名了一个自己也看不懂的单元测试名,然后在通过特性写一个中文,总体重复的工作量实在太多。而在 MSTestEnhancer 可以愉快使用中文的写法,直接在某个需要被测试的方法里面用字符串写明这个代码用来测试什么这样的代码将会比之前清真,写起来的代码量也少了很多

上面的代码还缺少一个被测试的 Foo 方法,现在写一下

        private void Foo(Func<int, string> func)
{
var str = func(1);
str = func(0);
}

此时的第一句调用 str = func(1) 返回的是空,因为没有定义,使用默认的返回值。第二句传入参数 0 返回值是 林德熙是逗比 因为上面定义

如上面代码写的,如果我期望定义的参数是一个范围而不是某个数,那么我需要采用 It 这个类的帮助

判断参数符合某个条件的任意参数,可以使用 Is 方法,如在传入任何的一个大于零的参数

  mock.Setup(func => func(It.Is<int>(n => n > 0))).Returns("林德熙是逗比");

这里可以使用的是委托,所以复杂的条件也可以自己写。另外 It 还提供很多其他的帮助方法,可以简化代码,这些自己写一下就知道

这里的 It 不仅可以在 Setup 使用,也可以在 Verify 方法使用,如判断用户传入小于0的参数的时候,这个方法被调用一次

 mock.Verify(func => func(It.Is<int>(n => n < 0)), Times.Once);

如果不要求传入的是什么参数,包括各种边界值都可能传入,那么请直接使用下面方法。下面代码表示传入的任意的 int 的参数就可以

 mock.Verify(func => func(It.IsAny<int>()), Times.Once);

另一个问题是判断调用次数,如果我期望的某个方法被调用两次如何写?

通过 Times.Exactly 可以指定某个方法就被调用某次

    mock.Verify(func => func(0), Times.Exactly(2));

表示这个方法重来没调用过可以使用 Never 请看代码

 mock.Verify(func => func(It.IsAny<int>()), Times.Never);

当然还有方法至少被调用多少次,方法最多被调用多少次等,这些很简单

我的小伙伴写了很多单元测试的博客,欢迎小伙伴访问

2019-8-31-dotnet-如何在-Mock-模拟-Func-判断调用次数的更多相关文章

  1. dotnet 如何在 Mock 模拟 Func 判断调用次数

    在 dotnet 程序有很好用的 Mock 框架,可以用来模拟各种接口和抽象类,可以用来测试某个注入接口的被调用次数和被调用时传入参数.本文告诉大家如何在 Mock 里面模拟一个 Func 同时模拟返 ...

  2. Mock 模拟测试简介及 Mockito 使用入门

    Mock 是什么mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法.这个虚拟的对象就是mock对象.mock对象就是真实对象在调试期间的代 ...

  3. 深入浅出的webpack4构建工具---比mock模拟数据更简单的方式(二十一)

    如果想要了解mock模拟数据的话,请看这篇文章(https://www.cnblogs.com/tugenhua0707/p/9813122.html) 在实际应用场景中,总感觉mock数据比较麻烦, ...

  4. Python 的mock模拟测试介绍

    如何不靠耐心测试 可能我们正在写一个社交软件并且想测试一下"发布到Facebook的功能",但是我们不希望每次运行测试集的时候都发布到Facebook上. Python的unitt ...

  5. agentzh 的 Nginx 教程(版本 2019.07.31)

    agentzh 的 Nginx 教程(版本 2019.07.31) agentzh 的 Nginx 教程(版本 2019.07.31) https://openresty.org/download/a ...

  6. Mock模拟数据,前后端分离

    安装 使用npm安装: npm install mockjs; 或直接<script src="http://mockjs.com/dist/mock.js">< ...

  7. vue-cli实现异步请求返回mock模拟数据

    在前后端分离开发的过程中,前端开发过程中,页面的数据显示一般都是写死的静态数据,也就是没有经过接口,直接写死在代码中的,在后端给出接口后,再替换为接口数据,为了减少对接成本,mock就出现了.通过预先 ...

  8. [模拟回调] demo1模拟用字符串调用js函数 demo2模拟springmvc controller回调页面js函数

    demo1. 模拟用字符串调用js 函数 function dataQuery() { var strFun = "testCallBack"; var strParam = &q ...

  9. 使用Socket&反射&Java流操作进行方法的远程调用(模拟RPC远程调用)

    写在前面 阅读本文首先得具备基本的Socket.反射.Java流操作的基本API使用知识:否则本文你可能看不懂... 服务端的端口监听 进行远程调用,那就必须得有客户端和服务端.服务端负责提供服务,客 ...

  10. springboot2.0入门(四)----mock模拟测试+单元测试

    一.本节主要记录模拟测试.单元测试: 二.mock 测试 1.1什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象 ...

随机推荐

  1. vue v-show指令

    demo: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  2. 文件的操作repeat

    #_author:来童星#date:2019/12/15import os#1# print(os.name)# nt------>windows操作系统#2 用于获取当前操作系统的换行符# p ...

  3. C/C++ ShowWindow()

    { ShowWindow(HWND,0);//不显示窗口 }

  4. thinkphp 模块化设计

    一个完整的ThinkPHP应用基于模块/控制器/操作设计,并且,如果有需要的话,可以支持多入口文件和多级控制器. ThinkPHP3.2采用模块化的架构设计思想,对目录结构规范做了调整,可以支持多模块 ...

  5. HTML基本案列

    <html> <head> <!-- meta :告诉浏览器,如何翻译汉字 http-equiv :content-type 内容类型 详细内容有后面的值指定 conte ...

  6. char类型在传参时接收不到数据的原因

    mybatis的原因!!!!! 数据库这个样子 在postman中调用接口:SQL select * from T_TRAIN_MARSHALLING where TRAIN_NUM is null ...

  7. Day 6:集合(set)

    集合(set)定义:由不同元素组成的集合,集合中是一组无序排列的可hash值,可以作为字典的key特性:集合里面数据类型是不可变的1.可变的数据类型:列表,字典2.不可变的数据类型:数字.元组.字符串 ...

  8. SpringAOP中的aop:config标签

    我们使用Spring的AOP功能的时候发现,我们使用普通的配置方式的时候,我们无法精确的确定将切面类中的哪个方法切入到哪个切入点上, 所以我们可以使用aop的专用标签来完成相关的配置.其中主要表现是使 ...

  9. Java学习之Java历史版本

    Java有三个版本,标准版Java SE,企业版Java EE,移动版Java ME.按理来说,每一种版本都会有自己的版本号,但是约定俗成:JDK版本号=Java SE版本号=Java版本号,这是因为 ...

  10. 04_Mybatis输入\出映射

    1. 输入映射 ​ 通过paramterType指定输入参数的类型,类型可以是简单类型.hashmap.pojo的包装类. 1.1 传递pojo的包装对象 1.需求 ​ 完成用户信息的综合查询,需要传 ...