你可能会用到的 Mock 小技巧

你可能会用到的 Mock 小技巧

Intro

最近看到阿迪分享了两篇 Mock 相关的文章,于是想把自己遇到的一些可能对你有帮助的一些小技巧分享一下,大概总结了一下,且看下文

AsyncEnumerable

在 C# 8 中引入了异步流,AsyncEnumerable,在有些类库中已经引入了这一语法,在 StackExchange.RedisHashScanAsync 的返回值就是 IAsyncEnumerable<HashEntry>

使用示例如下:

var dic = new Dictionary<string, string>();
await foreach (var entry in db.HashScanAsync(setName, "*"))
{dic[entry.Name] = entry.Value;
}

在 Mock 的时候,我们可以通过下面的 MockAsyncEnumerable 比较方便的指定一个 IEnumerable 对象来实现一个 IAsyncEnumerable 对象

private class MockAsyncEnumerable<T> : IAsyncEnumerable<T>
{private readonly IEnumerable<T> _data;public MockAsyncEnumerable(IEnumerable<T> data){_data = data;}public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()){return new MockAsyncEnumerator<T>(_data.GetEnumerator());}
}private class MockAsyncEnumerator<T> : IAsyncEnumerator<T>
{private readonly IEnumerator<T> _enumerator;public MockAsyncEnumerator(IEnumerator<T> enumerator){_enumerator = enumerator;}public ValueTask DisposeAsync(){_enumerator.Dispose();return default;}public ValueTask<bool> MoveNextAsync(){return new ValueTask<bool>(_enumerator.MoveNext());}public T Current => _enumerator.Current;
}

使用示例如下:

var entries = new HashEntry[10];
databaseMock.Setup(c => c.HashScanAsync(setName, "*", 200, 0, 0, CommandFlags.None)).Returns(new MockAsyncEnumerable<HashEntry>(entries));

HttpClient Mock

一个项目中经常会遇到调用第三方的 API,如何比较方便的 Mock 一个 HttpClient 的行为呢,我们可以通过自定义一个 HttpHandler 来实现自定义响应信息,通常我们需要根据不同的请求信息返回不同的响应,我们自定义了一个 MockHttpHandler 来实现比较方便的 Mock 第三方 API 的行为,实现如下:

internal class MockHttpHandler : DelegatingHandler
{private readonly Func<HttpRequestMessage, HttpResponseMessage> _getResponseFunc;public MockHttpHandler(Func<HttpRequestMessage, HttpResponseMessage> getResponseFunc){_getResponseFunc = getResponseFunc;}protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){return Task.FromResult(_getResponseFunc(request));}
}

使用示例如下:

using var client =new HttpClient(new MockHttpHandler(req => new HttpResponseMessage(HttpStatusCode.BadRequest))){BaseAddress = new Uri("https://api.weihanli.xyz/")};
//
using var httpClient = new HttpClient(new MockHttpHandler(request =>
{var statusCode = request.RequestUri.AbsoluteUri.Contains("templateId=1") ? HttpStatusCode.NotFound : (request.RequestUri.AbsoluteUri.Contains("templateId=2") ? HttpStatusCode.BadRequest : HttpStatusCode.InternalServerError);return new HttpResponseMessage(statusCode){Content = new StringContent(JsonConvert.SerializeObject(new{Code = statusCode.ToString(),Msg = "The template not exists"}))};
}))

MVC HttpContext Mock

HttpContext mock 示例:

var services = new ServiceCollection().AddScoped<CurrentUser>(sp => new CurrentUser(){UserID = 1,UserName = "admin"}).BuildServiceProvider();var mock = new Mock<HttpContext>();
// Mock HttpContext.User
mock.SetupGet(x => x.User).Returns(new ClaimsPrincipal(new ClaimsIdentity(new Claim[]{new Claim(ClaimTypes.Name, "admin"),new Claim(ClaimTypes.Email, "weihan.li@iherb.com"),}, JwtBearerDefaults.AuthenticationScheme)));
// Mock RequestServices
mock.Setup(x => x.RequestServices).Returns(services);var controller = new CommonController(NullLogger<CommonController>.Instance)
{ControllerContext = new ControllerContext() {HttpContext = mock.Object }
};

MVC ExceptionFilter test

有时我们会在项目里使用到 ExceptionFilter 来捕获 MVC 中未捕获的异常,如果想要针对自定义的 ExceptionFilter 写一些测试用例可以参考下面的测试用例:

[Fact]
public async Task ExceptionTest()
{var filters = new IFilterMetadata[]{new ResultExceptionFilter()};var exceptionContext = new ExceptionContext(new ActionContext(){HttpContext = new DefaultHttpContext(){RequestServices = new ServiceCollection().AddLogging().BuildServiceProvider()},RouteData = new RouteData(new RouteValueDictionary(){{"controller", "Test"},{"action", "Test"},}),ActionDescriptor = new ActionDescriptor(),}, filters){Exception = new NotImplementedException()};var invoker = new Mock<IActionInvoker>();invoker.Setup(x => x.InvokeAsync()).Callback(() =>{new ResultExceptionFilter().OnException(exceptionContext);}).Returns(Task.CompletedTask);await invoker.Object.InvokeAsync();// ...
}

Mock Data

字符串

在我们的代码中经常会出现对输入参数进行校验是否为空,对于这样的数据每次都取写一遍就会有点烦,所以写了一个自定义测试数据,就是返回 null/空字符串,实现代码如下:

public class NullOrEmptyStringDataAttribute : DataAttribute
{public bool IncludeWhitespace { get; set; }public override IEnumerable<object[]> GetData(MethodInfo testMethod){yield return new object[] { null };yield return new object[] { string.Empty };if (IncludeWhitespace){yield return new object[] { " " };}}
}

使用示例如下:

[Theory]
[NullOrEmptyStringData]
public void Test(string name)
{Assert.True(string.IsNullOrEmpty(name));
}[Theory]
[NullOrEmptyStringData(IncludeWhitespace=true)]
public void Test1(string name)
{Assert.True(string.IsNullOrWhitespace(name));
}

Number

对于 id 之类的数据,通过我们需要检查是否大于0,在写测试的时候需要考虑小于等于 0 的情况,通常我们也可以像上面那样做一个简单的封装,实现代码如下:

public class LessThanOrEqualDataAttribute : DataAttribute
{public int Value { get; set; }public override IEnumerable<object[]> GetData(MethodInfo testMethod){yield return new object[] { Value };yield return new object[] { Value - 1 };}
}

使用实例如下:

[Theory]
[LessThanOrEqualData]
public async Task GetCategoryIdInfo_BadRequest(int id)
{var result = await _controller.GetCategoryIdInfo(id, null);result.AssertCode(ErrorCode.BadRequest);
}

More

上面是一些我写测试用例的时候可能会用到的一些帮助类或 Mock 方法,希望能对你有所帮助~

你在写测试用例的过程中还有哪些觉得比较实用或者有哪些测试用例觉得比较难写呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mangos源码分析(2):服务器结构探讨之登录服的负载均衡

回想一下我们在玩wow时的操作流程&#xff1a;运行wow.exe进入游戏后&#xff0c;首先就会要求我们输入用户名和密码进行验证&#xff0c;验证成功后才会出来游戏世界列表&#xff0c;之后是排队进入游戏世界&#xff0c;开始游戏...  可以看到跟前面的描述有个很明显的不同&…

备受期待的Python深度学习来了

在这个酣畅淋漓的暑假结束后&#xff0c;深度学习的四大名著之一漂洋过海来见中国的程序员们啦&#xff0c;豆瓣评分9.5分的《Deep Learning with Python》&#xff0c;推出中译版——《Python深度学习》Deep Learning with PythonPython深度学习扫码购买优惠近30元&#xff01…

安装linux6.10 I386系统教程,一看就懂的Centos6.10安装教程

第一步将虚拟机安装完毕后&#xff0c;运行虚拟机进行到这个界面下(虚拟机安装及其配置&#xff0c;详见论坛内的博客分享在这就不在陈述)&#xff0c;&#xff1a;出现的是5条英文由上到下以此分别为&#xff1a;1.安装或升级2.基本的显卡驱动来安装系统(在有些操作系统无法识…

批量修改远程linux服务器密码

一、建立信任关系 192.168.9.203 为管理机 192.168.9.201 192.168.9.202 为远程linux服务器 1、在管理机生成证书、 [rootmanage ~]# ssh-keygen -t rsa复制代码Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter pas…

计算机是怎么知道两张图片相似的呢?

全世界有3.14 % 的人已经关注了数据与算法之美很多搜索引擎可以用一张图片&#xff0c;搜索互联网上所有与它相似的图片。你输入网片的网址&#xff0c;或者直接上传图片&#xff0c;Google就会找出与其相似的图片。下面这张图片是美国女演员Alyson Hannigan。上传后&#xff0…

WPF实现下拉框带图文和水印

WPF开发者QQ群&#xff1a; 340500857 有小伙伴需要实现ComboBox下拉框带水印&#xff0c;并且选择Item内容后水印默认从中间到顶部。Item需要展示图文&#xff0c;选择后的数据展示图文。欢迎转发、分享、点赞&#xff0c;谢谢大家~。效果如下&#xff1a;一、Xaml代码如下<…

linux 7.0查看防火墙状态,centos7查看防火墙状态

查看防火墙状态[rootVM_0_3_centos /]# firewall-cmd --statenot running[rootVM_0_3_centos /]# sudo systemctl status firewalld● firewalld.service - firewalld - dynamic firewall daemonLoaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor …

Google第一女神李飞飞,从洗碗工蜕变成为首席科学家

全世界有3.14 % 的人已经关注了数据与算法之美最近这几天&#xff0c;5岁孩子简历事件刷爆了朋友圈。批阅完朋友圈的文章&#xff0c;超模君心好累。别人家的孩子5岁已经每周3篇英语日记&#xff0c;而5岁我却还在玩泥巴&#xff0c;终于明白什么叫输在起跑线上了。即便输在了起…

如何注册java程序为windows服务

最近想找个软件来控制电脑的关机时间&#xff0c;在网上找了几个&#xff0c;都是可视化界面的可以设置具体的关机时间的软件。由于我想编写的关机程序是运行在别人机器上&#xff0c;只能让该机器在晚上17 点到23 点25 分才上网&#xff0c;到了23 点25 分就可以自动关机。为了…

通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权...

Oauth2授权&#xff0c;熟悉微信开发的同学对这个东西应该不陌生吧。当我们的应用系统需要集成第三方授权时一般都会做oauth集成&#xff0c;今天就来看看在Dapr的语境下我们如何仅通过配置无需修改应用程序的方式让第三方服务保护我们的API应用。目录&#xff1a;一、通过Dapr…

linux创建备用管理员,sql server 创建备用管理员和只读用户

-----------------------------------------------------------------------创建新的登录名use mastergoexec sp_addlogin loginame mysa , passwd 11goexec sp_addlogin loginame read , passwd 11go--修改密码--exec sp_password old null , new sa , loginame sa--exec…

宝宝学数学的第一套书,秒杀题海战术!上小学前应该这样学数学!

作为一个小学口心算特好、初高中也特别好的学霸。小木一直很关心孩子们的数学问题。我一直都在探索如何引领孩子走进数学的大门&#xff0c;启发他学数学的兴趣&#xff0c;以及把数学思维应用到生活中&#xff0c;而不仅仅是学会背数、四则运算、乘法口诀。孩子大多在3、4岁开…

使用 Azure Container Registry 储存镜像

Azure Container Registry&#xff08;容器注册表&#xff09;是基于 Docker Registry 2.0规范的托管专用 Docker 注册表服务。可以创建和维护 Azure 容器注册表来存储与管理专用的 Docker 容器映像和相关项目。Azure Container Registry 类似与阿里云的容器镜像服务。提供镜像…

在Android应用中使用Pull解析XML文件(传智播客视频笔记)

Service.java源码&#xff1a; package com.sinaapp.ssun.service; import java.io.InputStream; import java.io.OutputStream; import java.util.*; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlSerializer…

linux级别3怎么配置DNS,Linux下DNS服务器配置详解

6)辅助区域的文件基本和主区域的配置一样&#xff0c;就是不再需要在options块中加allow-transfer {}&#xff1b;&#xff0c;编辑named.rfc1912.zones文件&#xff0c;如下图进行添加&#xff1a;一定要将默认的"allow-update {none;}; "项&#xff0c;即将允许更新…

入门机器学习,这一步必不可少!

AI这个词相信大家都非常熟悉&#xff0c;近几年来人工智能圈子格外热闹&#xff0c;光是AlphoGo就让大家对它刮目相看。今天小天就来跟大家唠一唠如何进军人工智能的第一步——机器学习。在机器学习领域&#xff0c;Python已经成为了主流。一方面因为这门语言简单易上手&#x…

有趣的时钟

网址&#xff1a; http://chabudai.org/blog/?p59 转载于:https://blog.51cto.com/zhengchangbai/883557

.NET 中的 Worker Service 入门介绍

翻译自 Steve Gordon 2020年3月30日的文章 《WHAT ARE .NET WORKER SERVICES?》 [1]随着 .NET Core 3.0 的发布&#xff0c;ASP.NET 团队引入了一个新的 Worker Service 项目模板&#xff0c;该模板作为 .NET SDK 的一部分发布。在本文中&#xff0c;我将向您介绍这个新模板&a…

linux实验目的能学会什么意思,Linux实验.doc

Linux实验实验一&#xff1a;Linux系统的安装时间&#xff1a;一、实验目的1&#xff0e;了解Linux操作系统的内核版本和发行版本&#xff1b;2&#xff0e;掌握Fedora、RedHat操作系统的安装方法。二、实验内容和步骤&#xff1a;见教材第二章及相应课件。三、参考内容CD-ROM引…

为什么前后端分离了,你比从前更痛苦?

你有没有遇到过&#xff1a;前端代码刚写完&#xff0c;后端的接口又变了。接口文档永远都是不对的。测试工作永远只能临近上线才能开始。为什么前后端分离了&#xff0c;你比从前更痛苦&#xff1f;前后端分离早已经不是新闻&#xff0c;当真正分离之后确遇到了更多问题。要想…