2020-07-16

更优雅的在 Xunit 中使用依赖注入

更优雅的在 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) }}
  1. 移除 TestFramework assembly attribute
  2. 不再需要继承于 DependencyInjectionTestFramework
  3. 也因为上面的不需要继承,所以原本要 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 部分定义 XunitStartupAssemblyXunitStartupFullName,具体规则如下

<Project> <PropertyGroup> <XunitStartupAssembly>Abc</XunitStartupAssembly> <XunitStartupFullName>Xyz</XunitStartupFullName> </PropertyGroup></Project>
XunitStartupAssemblyXunitStartupFullNameStartup
Your.Test.Project.Startup, Your.Test.Project
AbcAbc.Startup, Abc
XyzXyz, Your.Test.Project
AbcXyzXyz, 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 中使用依赖注入出口易accapromoted傲基&泽宝的产品经理为什么都向她学习数据选品?了解Review的前世今生,实现10天1000个 VP Review堆积一个新店铺如何从零起步做到4000单?到海南特产购物旅游全攻略指南昆明旅游美食全攻略推荐给大家云南大理有哪些好玩的景点?大理古城旅游风景推荐

No comments:

Post a Comment