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. sql server 的存储过程

    存储过程说白了就是一堆 SQL 的合并.中间加了点逻辑控制. 存储过程运行流程 创建不带参数存储过程 --创建存储过程 if (exists (select * from sys.objects wh ...

  2. Java Queue队列

    前言 Queue队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作,LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用.  ...

  3. 校园商铺-2Logback配置与使用-1Logback介绍

    日志的作用: 1.故障定位 2.显示程序运行状态 好的日志记录方式可以提供给我们足够多定位问题的依据,因此我们引入logback组件来进行日志的记录 1. Logback标准配置 1.1 Logbac ...

  4. 专访阿里云MVP王俊杰:开发者的超能力是用技术让世界更美好

    [王俊杰:阿里云MVP,陕西创博网络科技有限公司总经理.大数据与物联网的爱好者与实践者. 8年以上互联网从业经验,曾从事军工相关仿真分析软件研发与集成.4年以上大数据系统开发经验.目前正与天水市秦州区 ...

  5. 尚学linux课程---10、linux环境下安装python

    尚学linux课程---10.linux环境下安装python 一.总结 一句话总结: 直接在官网下载python的源码包即可,然后在linux下安装 linux下安装软件优先想到的的确是yum,但是 ...

  6. WinDBG常用断点命令

    WinDBG提供了多种设断点的命令: bp 命令是在某个地址 下断点, 可以 bp 0x7783FEB 也可以 bp MyApp!SomeFunction . 对于后者,WinDBG 会自动找到MyA ...

  7. day24 面向对象设计part1

    #!/usr/bin/env python # -*- coding:utf-8 -*- # ----------------------------------------------------- ...

  8. 浅析ES的_source、_all、store、index

    Elasticsearch中有大量关键概念容易混淆,对于初学者来说是噩梦: _source字段里存储了什么? index属性的作用是什么? 何时应该开启_all字段? store属性和_source字 ...

  9. java编程规约一

    提高开发效率,比较重视代码规范,尤其是可扩展性和可维护性,以及可读性.如果你是一个刚进公司的开发者,最好先问问前辈是否有 内部的开发规范,花点时间过一遍.即使提交代码没有review的步骤,自己心里应 ...

  10. js 禁止/允许页面滚动

    参考:https://blog.csdn.net/huangfu_chunfeng/article/details/46429997         https://www.cnblogs.com/w ...