更优雅的在 Xunit 中使用依赖注入
Xunit.DependencyInjection 7.0 发布了
Intro
上次我们已经介绍过一次大师的 Xunit.DependencyInjection
https://www.cnblogs.com/weihanli/p/xuint-dependency-injection.html ,最近大师完成了 7.0 的重构并且已经正式发布,已经可以直接安装使用了
7.0 为我们带来了更好的编程体验,在 6.x 的版本中,我们的 Startup
需要继承于 DependencyInjectionTestFramework
而且需要设置一个 assembly attribute,这在 7.0 中都不需要了,下面我们来看看有了哪些变化
Startup 的变化
首先来看大师给出的 diff
-[assembly: TestFramework("Your.Test.Project.Startup", "Your.Test.Project")]
namespace Your.Test.Project
{
- public class Startup : DependencyInjectionTestFramework
+ public class Startup
{
- public Startup(IMessageSink messageSink) : base(messageSink) { }
- protected void ConfigureServices(IServiceCollection services)
+ public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IDependency, DependencyClass>();
}
- protected override IHostBuilder CreateHostBuilder() =>
- base.CreateHostBuilder(assemblyName)
- .ConfigureServices(ConfigureServices);
- protected override void Configure(IServiceProvider provider)
+ public void Configure(IServiceProvider provider)
}
}
- 移除
TestFramework
assembly attribute - 不再需要继承于
DependencyInjectionTestFramework
- 也因为上面的不需要继承,所以原本要
override
的方法可以不override
了,原来是protected
的方法现在需要改成public
新的 Startup 解析
我把上一篇文章写的示例用升级到了新的版本
需要实现自己的一个 Startup
,在 Startup
里进行服务注册和初始化
namespace XUnitDependencyInjectionSample
{
public class Startup
{
// 自定义 HostBuilder ,可以没有这个方法,没有这个方法会使用默认的 hostBuilder,通常直接使用 `ConfigureHost` 应该就够用了
// public IHostBuilder CreateHostBuilder()
// {
// return new HostBuilder()
// .ConfigureAppConfiguration(builder =>
// {
// // 注册配置
// builder
// .AddInMemoryCollection(new Dictionary<string, string>()
// {
// {"UserName", "Alice"}
// })
// .AddJsonFile("appsettings.json")
// ;
// })
// .ConfigureServices((context, services) =>
// {
// // 注册自定义服务
// services.AddSingleton<IIdGenerator, GuidIdGenerator>();
// if (context.Configuration.GetAppSetting<bool>("XxxEnabled"))
// {
// services.AddSingleton<IUserIdProvider, EnvironmentUserIdProvider>();
// }
// })
// ;
// }
// 自定义 host 构建
public void ConfigureHost(IHostBuilder hostBuilder)
{
hostBuilder
.ConfigureAppConfiguration(builder =>
{
// 注册配置
builder
.AddInMemoryCollection(new Dictionary<string, string>()
{
{"UserName", "Alice"}
})
.AddJsonFile("appsettings.json")
;
})
.ConfigureServices((context, services) =>
{
// 注册自定义服务
services.AddSingleton<IIdGenerator, GuidIdGenerator>();
if (context.Configuration.GetAppSetting<bool>("XxxEnabled"))
{
services.AddSingleton<IUserIdProvider, EnvironmentUserIdProvider>();
}
})
;
}
// 支持的形式:
// ConfigureServices(IServiceCollection services)
// ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
// ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection services)
public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
{
services.TryAddSingleton<CustomService>();
}
// 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法
public void Configure(IServiceProvider applicationServices, IIdGenerator idGenerator)
{
// 有一些测试数据要初始化可以放在这里
// InitData();
}
}
}
在新的版本中 Startup
和 asp.net core 里的 Startup
更加相像了,
会多一个 CreateHostBuilder
/ConfigureHost(IHostBuilder)
的方法,允许用户自定义 Host 的构建,也可以没有这个方法
ConfigureServices
方法允许用户增加 HostBuilderContext
作为参数,可以通过 hostBuilderContext
来获取配置信息,也可以在 CreateHostBuilder
/ConfigureHost(IHostBuilder)
里注册也是一样的
注册配置/服务和 asp.net core 里一模一样,有数据或配置需要在项目启动时初始化的,可以放在 Configure
方法做,有点类似于 asp.net core 里 Startup
中的 Configure
方法,可以将需要的服务作为方法参数,执行时会自动从注册的服务中获取
Startup 的寻找方法
默认的 Startup
通常是 ProjectName.Startup
,通常在项目根目录下创建一个 Startup
是不需要配置的,如果不是或不起作用,可以参考下面 Startup 的寻找规则
如果要使用一个特别的 Startup
, 你可以通过在项目文件的 PropertyGroup
部分定义 XunitStartupAssembly
和 XunitStartupFullName
,具体规则如下
<Project>
<PropertyGroup>
<XunitStartupAssembly>Abc</XunitStartupAssembly>
<XunitStartupFullName>Xyz</XunitStartupFullName>
</PropertyGroup>
</Project>
XunitStartupAssembly | XunitStartupFullName | Startup |
---|---|---|
Your.Test.Project.Startup, Your.Test.Project | ||
Abc | Abc.Startup, Abc | |
Xyz | Xyz, Your.Test.Project | |
Abc | Xyz | Xyz, Abc |
More
除了上面的 Startup
的改动之外,新版本还支持了 xunit 中 fixture 的依赖注入,这是由一个外国小哥提的 PR, 详见:https://github.com/pengweiqhca/Xunit.DependencyInjection/pull/21
有了这个神器,在测试代码中使用依赖注入要方便很多了,还没有用起来的可以准备上手了~~
Reference
- https://github.com/pengweiqhca/Xunit.DependencyInjection
- https://github.com/WeihanLi/SamplesInPractice/tree/master/XUnitDependencyInjectionSample
更优雅的在 Xunit 中使用依赖注入的更多相关文章
- 在 XUnit 中使用依赖注入
在 XUnit 中使用依赖注入 Intro 之前写过一篇 xunit 的依赖注入相关的文章,但是实际使用起来不是那么方便 今天介绍一个基于xunit和微软依赖注入框架的"真正"的依 ...
- 在 xunit 测试项目中使用依赖注入
在 xunit 测试项目中使用依赖注入 Intro 之前写过几篇 xunit 依赖注入的文章,今天这篇文章将结合我在 .NET Conf 上的分享,更加系统的分享一下在测试中的应用案例. 之所以想分享 ...
- 在WPF中使用依赖注入的方式创建视图
在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...
- Spring学习(一)——Spring中的依赖注入简介【转】
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring. ...
- 转: 理解AngularJS中的依赖注入
理解AngularJS中的依赖注入 AngularJS中的依赖注入非常的有用,它同时也是我们能够轻松对组件进行测试的关键所在.在本文中我们将会解释AngularJS依赖注入系统是如何运行的. Prov ...
- 理解AngularJS中的依赖注入
点击查看AngularJS系列目录 理解AngularJS中的依赖注入 AngularJS中的依赖注入非常的有用,它同时也是我们能够轻松对组件进行测试的关键所在.在本文中我们将会解释AngularJS ...
- ABP中的依赖注入思想
在充分理解整个ABP系统架构之前首先必须充分了解ABP中最重要的依赖注入思想,在后面会具体举出一些实例来帮助你充分了解ABP中的依赖注入思想,在了解这个之前我们首先来看看什么是依赖注入?来看看维基百科 ...
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)
相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...
随机推荐
- 【01JMeter基础】测试计划
测试计划 整个脚本的集合根目录,所有线程组集合的承载,可以添加线程组.测试片段.非测试元件.配置元件.监听器.定时器.前置/后置处理起器.断言等 一.用户自定义变量 可以使用在所有的线程组中,通过${ ...
- Java并发--ReentrantLock原理详解
ReentrantLock是什么? ReentrantLock重入锁,递归无阻塞的同步机制,实现了Lock接口: 能够对共享资源重复加锁,即当前线程获取该锁,再次获取不会被阻塞: 支持公平锁和非公平锁 ...
- MFC基于CAsyncSocket套接字客户端代码示范
MFC基于CAsyncSocket套接字客户端代码示范 https://blog.csdn.net/txwtech/article/details/93016190
- java map里面进行ASCII 码从小到大排序(字典序)
public static String getAsciiSort(Map<String, Object> map) { List<Entry<String, Object&g ...
- Python实用笔记 (27)面向对象高级编程——使用枚举类
枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例.Python提供了Enum类来实现这个功能: from enum import Enum Month = Enum('Mon ...
- 【Flutter实战】自定义滚动条
老孟导读:[Flutter实战]系列文章地址:http://laomengit.com/guide/introduction/mobile_system.html 默认情况下,Flutter 的滚动组 ...
- 【数位dp】CF 55D Beautiful numbers
题目 Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer n ...
- 一张PDF了解JDK9 GC调优秘籍-附PDF下载
目录 简介 Oracle中的文档 JDK9中JVM参数的变化 废弃的JVM选项 不推荐(Deprecated)的JVM选项 被删除的JVM参数 JDK9的新特性Application Class Da ...
- 使用scrapy实现去重,使用Redis实现增量爬取
面试场景: 要求对正在爬取的内容与mysql数据库中的数据进行比较去重 解决方式: 通过Redis来作为中间件,通过url来确保爬过的数据不会再爬,做到增量爬取. Redis数据库其实就是一个中间件, ...
- Docker环境下Java应用的最大内存和堆内存的设置
Docker环境下Java应用的最大内存和堆内存的设置 1. 设置应用允许使用的最大内存 通过docker run(创建一个新的容器并运行)命令中设置-m来进行设置.案例如下所示. docker r ...