首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

.NET 8 Moq mock GetRequiredKeyedService Setup报错

编程知识
2024年08月30日 14:41

.NET 8 Moq mock GetRequiredKeyedService Setup报错

项目代码里有地方用到IServiceProvider.GetRequiredKeyedService<T>来解析服务,在写单元测试时需要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最终调用的接口方法,然后再mock即可。

首先看下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不开源,看不到源代码,还是有点头疼。

From:https://www.cnblogs.com/netry/p/18388859/dotnet-moq-mock-GetRequiredKeyedService
本文地址: http://www.shuzixingkong.net/article/1588
0评论
提交 加载更多评论
其他文章 VS Code 代码片段指南: 从基础到高级技巧
前言 “ 系列首发于公众号『非同质前端札记』 ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。 今天咱们来聊聊 VS Code 里的自定义代码片段。 这玩意儿简直是提升编码效率的神器, 用好了能让你敲代码更方便! 不管你是刚入行的菜鸟还是身经百战的老兵,这篇攻略都能让你在代码片段的
VS Code 代码片段指南: 从基础到高级技巧
Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储
Clobotics 是一家将计算机视觉和机器学习技术应用于风电以及零售行业的企业。在风电行业,Clobotics 利用无人机对风力发电机叶片进行检查,显著降低了对人工作业的依赖。在零售领域,公司通过分析捕获的包装商品图像来提供基于实时数据的洞察,以增加销售额并减少运营成本。 存储方面,Cloboti
Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储 Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储 Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储
基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型
过去的几个月,我们目睹了使用基于 transformer 模型作为扩散模型的主干网络来进行高分辨率文生图 (text-to-image,T2I) 的趋势。和一开始的许多扩散模型普遍使用 UNet 架构不同,这些模型使用 transformer 架构作为扩散过程的主模型。由于 transformer
基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型 基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型 基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型
从代码到产品,我的IT职业成长之路
每个人的职业生涯都是一段充满转折和挑战的旅程,当然每一次职业转型都是一次重新定义自己的机会,从2015年开始,当时我刚踏入IT行业,成为一名Java开发者,后来随着时间的推移,我的职业方向逐渐转向了前端开发者,埋头于代码的世界。最终在2018年找到了属于自己的职业定位——产品经理。一路走来,我不断扩
从代码到产品,我的IT职业成长之路
uni-app之camera组件-人脸拍摄
小程序录制视频;10-30秒;需要拍摄人脸,大声朗读数字(123456)这种。 1.camera组件 camera页面内嵌的区域相机组件。注意这不是点击后全屏打开的相机 camera只支持小程序使用;官网链接 1.2 效果图 1.3 页面布局 camera 设置宽100%,高度通过uni.getSy
uni-app之camera组件-人脸拍摄 uni-app之camera组件-人脸拍摄 uni-app之camera组件-人脸拍摄
NET Core 多身份校验与策略模式
背景需求: 系统需要对接到XXX官方的API,但因此官方对接以及管理都十分严格。而本人部门的系统中包含诸多子系统,系统间为了稳定,程序间多数固定Token+特殊验证进行调用,且后期还要提供给其他兄弟部门系统共同调用。 原则上:每套系统都必须单独接入到官方,但官方的接入复杂,还要官方指定机构认证的证书
NET Core 多身份校验与策略模式 NET Core 多身份校验与策略模式 NET Core 多身份校验与策略模式
倾斜摄影osgb格式文件,进行坐标转换
倾斜摄影OSGB格式的文件,很棘手,今天需要把osgb放到UE中渲染。碰到的问题如下: 1、osgb文件导进去后,Z轴不想上,是歪的,小人放进去后,就斜站在马路上。 2、根本原因是坐标系,UE的插件cesium for UE支持WGS84坐标(wkid:4326)。 怎么解决问题呢? 1、当然是问G
containerd:配置https私有镜像仓库的最新方法
随着containerd应用越来越广泛,我们必须紧跟官网的节奏。 之前配置https私有镜像仓库的方法比较繁琐,并且不易梳理,下边介绍一下目前最新的配置方法。 配置https私有镜像仓库 我假设你现在已经有私有仓库并且是https 再假设你的harbor域名是harbor.example.cn 你只