.NET 8 Moq mock GetRequiredKeyedService Setup报错
.NET 8 Moq mock GetRequiredKeyedService Setup报错
代码有地方用到了IServiceProvider.GetRequiredKeyedService来解析服务,写单元测试时也需要Mock它,本以为像下面这些些就可以
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(x => x.GetRequiredKeyedService<AAA>(It.IsAny<BBB>())).Returns(new CCC());
没想到报错了:
Test method threw exception:
System.NotSupportedException: Unsupported expression: x => x.GetRequiredKeyedService(It.IsAny<Type>(), It.IsAny<object>())
Extension methods (here: ServiceProviderKeyedServiceExtensions.GetRequiredKeyedService) may not be used in setup / verification expressions.
Stack Trace:
Guard.IsOverridable(MethodInfo method, Expression expression) line 87
MethodExpectation.ctor(LambdaExpression expression, MethodInfo method, IReadOnlyList`1 arguments, Boolean exactGenericTypeArguments, Boolean skipMatcherInitialization, Boolean allowNonOverridable) line 236
ExpressionExtensions.<Split>g__Split|5_0(Expression e, Expression& r, MethodExpectation& p, Boolean assignment, Boolean allowNonOverridableLastProperty) line 256
ExpressionExtensions.Split(LambdaExpression expression, Boolean allowNonOverridableLastProperty) line 170
Mock.SetupRecursive[TSetup](Mock mock, LambdaExpression expression, Func`4 setupLast, Boolean allowNonOverridableLastProperty) line 728
Mock.Setup(Mock mock, LambdaExpression expression, Condition condition) line 562
Mock`1.Setup[TResult](Expression`1 expression) line 645
有点奇怪,难道GetRequiredKeyedService不是接口方法?查看.NET源代码,果然,GetRequiredKeyedService是IServiceProvider的扩招方法,我们知道Moq是不支持Setup扩招方法的。
/// <summary>
/// Get service of type <typeparamref name="T"/> from the <see cref="IServiceProvider"/>.
/// </summary>
/// <typeparam name="T">The type of service object to get.</typeparam>
/// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the service object from.</param>
/// <param name="serviceKey">An object that specifies the key of service object to get.</param>
/// <returns>A service object of type <typeparamref name="T"/>.</returns>
/// <exception cref="System.InvalidOperationException">There is no service of type <typeparamref name="T"/>.</exception>
public static T GetRequiredKeyedService<T>(this IServiceProvider provider, object? serviceKey) where T : notnull
{
ThrowHelper.ThrowIfNull(provider);
return (T)provider.GetRequiredKeyedService(typeof(T), serviceKey);
}
原因找到就好半了,翻看源码,一步步找到IServiceProvider.GetRequiredKeyedService最终调用的接口方法然后再mocke即可
首先看下requiredServiceSupportingProvider.GetRequiredKeyedService(serviceType, serviceKey)调的是什么方法
/// <summary>
/// IKeyedServiceProvider is a service provider that can be used to retrieve services using a key in addition
/// to a type.
/// </summary>
public interface IKeyedServiceProvider : IServiceProvider
{
/// <summary>
/// Gets the service object of the specified type.
/// </summary>
/// <param name="serviceType">An object that specifies the type of service object to get.</param>
/// <param name="serviceKey">An object that specifies the key of service object to get.</param>
/// <returns> A service object of type serviceType. -or- null if there is no service object of type serviceType.</returns>
object? GetKeyedService(Type serviceType, object? serviceKey);
/// <summary>
/// Gets service of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/> implementing
/// this interface.
/// </summary>
/// <param name="serviceType">An object that specifies the type of service object to get.</param>
/// <param name="serviceKey">The <see cref="ServiceDescriptor.ServiceKey"/> of the service.</param>
/// <returns>A service object of type <paramref name="serviceType"/>.
/// Throws an exception if the <see cref="IServiceProvider"/> cannot create the object.</returns>
object GetRequiredKeyedService(Type serviceType, object? serviceKey);
}
可以看到IKeyedServiceProvider也是继承了IServiceProvider接口,这就更好办了,我们直接Mock IKeyedServiceProvider并Setup即可,将用到IServiceProvider的地方,换成IKeyedServiceProvider,代码如下:
var serviceProvider = new Mock<IKeyedServiceProvider>();
serviceProvider.Setup(x => x.GetRequiredKeyedService(It.IsAny<AAA>(), It.IsAny<BBB>())).Returns(new CCC());
运行测试,完美。
总结
解决这个问题并不困难,但是如果.Net不开源,看不到源代码,还是有点头疼。
.NET 8 Moq mock GetRequiredKeyedService Setup报错的更多相关文章
- cap deploy:setup报错
今天部署cap的时候,setup出现以下错误: 查询半天未果,不过最后还是在google找到了,可见度娘极为不靠谱! I had the same error on deploy:setup with ...
- Mac Mojave(10.14.1)执行Matlab的mex报错
先装了matlab2018b,发现很频繁的crash,同时考虑到要跑的代码在>=2017a时就计算错误,于是转战matlab2016b matlab2016b安装后,执行mex -setup报错 ...
- Selenium Grid 运行报错 Exception thrown in Navigator.Start first time ->Error forwarding the new session Empty pool of VM for setup Capabilities
Selenium Grid 运行报错 : Exception thrown in Navigator.Start first time ->Error forwarding the new se ...
- python setup.py install 报错ImportError: No module named setuptools
学习光荣之路python课程时,使用python setup.py install安装其他模块时,第一次安装某模块成功了.安装另一模块却报错ImportError: No module named s ...
- pip安装mysql-python报错:Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-enRreC/mysql-python/
公司业务开发,用python开发网站;需要使用模块MySQLdb. 我直接pip install MySQLdb,当然不成功了,模块名字因该是mysql-python pip install mysq ...
- python pip install 报错TypeError: unsupported operand type(s) for -=: 'Retry' and 'int' Command "python setup.py egg_info" failed with error code 1 in
pip install http://download.pytorch.org/whl/cu80/torch-0.2.0.post3-cp27-cp27mu-manylinux1_x86_64.whl ...
- mock测试SpringMVC controller报错
使用mock测试Controller时报错如下 java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig at org.spr ...
- python setup.py install 报错:error: [WinError 3] 系统找不到指定的路径。: 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\PlatformSDK\\lib
Outline 在通过 setup.py 安装python模块时,遇到了以下报错: # 执行 python setup.py install # 报错: error: [WinError 3] 系统找 ...
- python setup.py install 报错
python setup.py install 报错信息 [root@VM_25_28_centos psutil-2.0.0]# python setup.py install running in ...
- python下pip 安装 pyautogui报错Command "python setup.py egg_info" failed with error code 1 in C:\Users\Administrator\AppData\Local\Temp\pip-install-svhtepho\pygetwindow\
python装的3.6 64位,使用命令pip install pyautogui 或者pip install -U pyautogui 都失败了 报错如下: Command "python ...
随机推荐
- Spring的AOP快速实现通用日志打印
需求分析 针对VideoService接口实现日志打印 三个核心包 spring-aop:AOP核心功能,例如代理工厂 aspectjweaver:简单理解,支持切入点表达式 aspectjrt:简单 ...
- PHP 缓存技术
PHP 缓存介绍 什么是缓存 数据交换的缓冲区(称作Cache) 临时文件交换区 缓存作用 减少网络延迟,加快页面打开速度 减少数据查询次数,降低数据库压力 降低系统负荷,极大的提升系统性能 常用缓存 ...
- [项目自荐] 交叉编译njs并使用Nginx搭建自由的个人网盘:vList5
这个博客好久没有打理了,最近才想起来 这篇文章是以下 5 篇文章的组合,希望这个免费的项目能实现他的初衷吧 vList5:部署指南 vList5.3 全面加密,从我做起 njs 从入门(交叉编译)到入 ...
- CF1468N 题解
洛谷链接&CF 链接 题目简述 共有 \(T\) 组数据,对于每组数据: 有三个桶,五种垃圾,每个桶有固定的容量. 前三种垃圾分别放入三种桶中,第四种垃圾可以放进 \(1,3\) 桶中,第五种 ...
- JVM系列(一) -浅谈虚拟机的成长史
一.摘要 众所周知,Java 经过多年的发展,已经从一门单纯的计算机编程语言,发展成了一套成熟的软件解决方案.从互联网到企业平台,Java 是目前使用最广泛的编程语言. 以下这段内容是来自 Java ...
- Python版RNA-seq分析教程:差异表达基因分析
Bulk RNA-seq 分析的一个重要任务是分析差异表达基因,我们可以用 omicverse包来完成这个任务.对于差异表达分析而言,首先,我们可> 以先将 gene_id 改为 gene_na ...
- LeetCode654. 最大二叉树
题目链接:https://leetcode.cn/problems/maximum-binary-tree/description/ 题目叙述 给定一个不重复的整数数组 nums . 最大二叉树 可以 ...
- 文件系统(十一):Linux Squashfs只读文件系统介绍
liwen01 2024.07.21 前言 嵌入式Linux系统中,squashfs文件系统使用非常广泛.它主要的特性是只读,文件压缩比例高.对于flash空间紧张的系统,可以将一些不需要修改的资源打 ...
- 【Layui】09 动画 Anim
文档地址: https://www.layui.com/demo/anim.html 8种动画 <fieldset class="layui-elem-field layui-fiel ...
- TensorBoard标量图中的平滑曲线是如何做的平滑?—— tensorflow TensorBoard标量图中“平滑”参数背后的数学原理是什么?—— 指数移动平均(EMA)
TensorFlow的tensorboard的平滑曲线的实现代码: 使用"指数移动平均"技术实现. 地址: https://github.com/tensorflow/tensor ...