在 xunit 测试项目中使用依赖注入

在 xunit 测试项目中使用依赖注入

Intro

以前写过几篇 xunit 依赖注入的文章,今天这篇文章将结合我在 .NET Conf 上的分享,更加系统的分享一下在测试中的应用案例。git

之因此想分享这个话题是由于我以为在咱们开发过程当中测试是很是重要的一部分,高质量项目的一个重要指标就是测试覆盖率,同时依赖注入已是一个现代化应用中不可缺乏的一部分,咱们的 .NET Core 也是从一开始就集成了依赖注入,依赖注入对于测试项目也是不能缺席的。github

xunit 是 .net 里目前使用的最多的测试组件,Xunit.DependencyInjection 是大师写的一个 xunit 依赖注入的扩展,它是基于微软的 GenericHost(通用主机) 来实现的,使用它咱们能够很轻松的实现依赖注入,很好的和 .NET Core 作集成。web

How it works

那它是如何工做的呢?咱们一块儿来看一下它的执行流程,它的执行流程分为四步app

首先须要构建一个 Host,而后启动这个 Host,启动完成后执行测试用例,最后终止这个 Host框架

执行流程

Host 又是如何构建的呢?咱们一块儿看一下,Host 的构建也是分为四步asp.net

第一步,建立一个 HostBuilder,大多数状况下咱们不须要用这个方法,使用默认的实现就好ide

第二步,Host 配置,对 Host 作一些自定义配置学习

第三步,服务配置,注册须要的服务测试

第四步,Configure,能够作一些初始化的配置,好比配置初始化以及测试数据的初始化等ui

Host构建流程

咱们能够在测试项目里建立一个 Startup 类来控制 Host 的构建过程

示例

接着咱们来看一些实际的测试示例,示例分为三部分,首先是一些基本用法,而后是和其余组件的集成,最后是一些扩展用法

Get Started

首先来看一下 Startup 的用法,这个 Startup 和 asp.net core 里的 Startup 是很像的,不管是使用方式上仍是实现上都是相似的,有兴趣的能够看一下源码对比一下,咱们来看一下使用方式,经过下面的示例来感觉一下

若是你只须要注册服务,直接在 Startup 中添加一个 ConfigureServices 方法,在这个方法中注册本身须要的服务便可,和 asp.net core 并没有太多不一样

若是你须要作一些初始化的工做,能够加一个 Configure 方法,在这个方法中实现本身的初始化逻辑就能够了,若是初始化的时候须要获取注入的服务实例,直接做为方法参数就能够,相似于 asp.net core 中 Configure 方法,只是不须要配置 Http 请求管道

若是你须要使用的配置,须要使用 Configuration,能够在 ConfigureHost 方法中经过 ConfigureHostConfiguration 扩展方法注册本身的配置

若是须要在注册服务的时候用到配置,能够在 ConfigureServices 方法中添加一个 HostBuildContext 的参数,HostBuilderContext 中的 Configuration 对象就是在 ConfigureHost 中注册的配置

若是须要在 Configure 方法中使用配置,直接添加一个 IConfiguration 的方法参数就能够了

咱们再来看一下,如何在测试用例中使用注入的服务,通常状况下咱们会直接经过构造器注入,在构造方法中添加须要注入的服务便可,除此以外咱们还能够经过方法参数注入,结合 InlineDataMemeberData 使用,来看一下这个示例

IoC/AOP Integration

接着咱们来看一下和其余组件的集成,AutoFac 是一个很流行的 IOC 组件,AspectCore 是柠檬大佬写的一个 AOP 框架,咱们以这两个为例子来看一下如何集成第三方的依赖注入和 AOP 组件,前面咱们已经提到它是基于微软的 GenericHost 实现的,而 asp.net core 从 3.0 开始也是基于 GenericHost 实现的,因此在 asp.net core 里怎么集成,在这里也是同样的,来看一下示例,只须要使用对应的 ServiceProviderFactory 就能够了,是否是很简单呢

Test Server Integration

而后咱们来看一下如何和 TestServer 作集成,TestServer 主要用于集成测试,使用 TestServer 的好处在于它是基于内存进行交互的没有真正的 HTTP 请求和 TCP 连接,会很是的高效,并且也不会监听某一个端口,因此不会有端口权限的问题。

TestServer 的使用主要有两步,首先是服务的注册,可使用 IHostBuilderIWebHostBuilderUseTestServer 扩展方法注册 TestServer,可使用 IHostGetTestClient 扩展方法来注册和 TestServer 进行交互的 HttpClient

服务注册好以后就能够在测试用例里经过注入的 HttpClient 请求 API 或页面了,能够参考这个例子

Extensions

Hosted Service

而后咱们来看一些扩展用法,IHostedService 能够用来实现一些初始化的操做或者后台服务,咱们可使用 IHostedService 来实现对应用的 Ready 检查,应用 Ready 以后再开始执行测试用例,这在有些场景下是颇有用的

咱们在 k8s 中部署的应用通常都会有一个 HealthCheck/ReadinessCheck 的接口来供 k8s 的 liveness/readiness 探针来探测应用的状态,只有应用 Ready 以后才会对外部提供服务

这个示例就是一个使用 IHostedService 来实现等待应用 Ready 后再开始执行测试用例的一个 demo

注意:这里的等待不能在 StartupConfigure 方法中执行,由于 Configure 的执行是在调用 Host 的 StartAsync 方法以前执行的,而此时 webServer 尚未启动,因此是不能获取到 TestClient 的,而咱们经过 HostedService 就能够在 Web Server 启动以后再执行咱们的等待 Ready 逻辑

ITestOutputHelperAccessor

在测试中若是想要输出一个日志的话只能借助于 ITestOutputHelper 来输出,直接使用 Console.Write[Line] 是看不到任何输出的,ITestOutputHelper 只能在测试用例中使用,在测试服务中是不能使用的,Xunit.DependencyInjection 提供了一个 ITestOutputHelperAccessor 的服务,相似于 IHttpContextAccessor,咱们能够借助它来在自定义的服务中获取 ITestOutputHelper 来输出日志

这里是一个简单的示例

Logging

再来看一个 OutputHelperAccessor 的实际应用,Xunit.DependencyInjection 提供了一个 Logging 的扩展,使得咱们能够把测试过程当中的日志输出出来,更好的帮助咱们调试

集成方式也比较简单,能够参考这个示例,引用 Xunit.DependencyInjection.Logging 以后,在 LoggerFactory 中注册 XunitTestOutputLoggerProvider 便可

能够看到咱们的日志直接输出出来了,默认的日志级别是 Information ,因此 Debug 级别的日志没有输出出来,有须要的话能够在注册的时候提供一个委托来控制是否要输出日志

Project Template

为了方便你们使用,咱们提供了一个项目模板,能够经过一个命令就能够直接建立好一个测试项目,会包含一个默认的 Startup 再也不须要本身去写方法了,使用的时候只须要根据须要作删减就能够了

默认的 TargetFramework 使用的是 netcoreapp3.1,能够经过 -f/--franework 指定本身想要使用的目标框架,好比说想要生成 net 5.0 的项目只须要指定 -f net5.0 就能够了

生成的内容以下所示:

More

最后列出来了一些可能会有帮助的连接,第一个是项目的源代码,第二个是 PPT 中全部示例的源代码,后面的是使用到的 Nuget 包。

这个 xunit 扩展的代码实现是很是值得学习的,有不少和 asp.net core 的实现是很像的,有须要的能够去看看源码学习一下。

但愿个人分享对你们有所帮助,你们在使用过程当中有遇到任何问题均可以随时联系我或者直接在 Github 上建 issue。

Reference

相关文章
相关标签/搜索