当前位置:网站首页>use Xunit.DependencyInjection Transformation test project
use Xunit.DependencyInjection Transformation test project
2020-11-07 21:03:00 【Irving the procedural ape】
Use Xunit.DependencyInjection Transformation test project
Intro
This article has been delayed for a long time , It has been introduced before Xunit.DependencyInjection This project , This project was written by a master Xunit Based on Microsoft GenericHost and An extension library for dependency injection implementation , It can make it easier for you to implement dependency injection in test projects , And I think another good point is that it can better control the operation process , For example, many initialization operations are done before starting the test , Better process control .
Recently, most of our company's testing projects are based on Xunit.DependencyInjection Transformed , The effect is very good .
Recently, I started my test project manually from the original one Web Host It's based on Xunit.DepdencyInjection To use , At the same time, it is also preparing for the update of integration test of a project of our company , It's delicious to use ~
I think Xunit.DependencyInjection Solved my two big pain points , One is that dependency injection code doesn't write well , One is a simpler process control process , Here is a general introduction to
XUnit.DependencyInjection Workflow
Xunit.DepdencyInjection The main process is DependencyInjectionTestFramework in , See https://github.com/pengweiqhca/Xunit.DependencyInjection/blob/7.0/Xunit.DependencyInjection/DependencyInjectionTestFramework.cs
First of all, I will try to find the... In the project Startup , This Startup Very similar to asp.net core Medium Startup, Almost exactly , It's just a little different , Startup Dependency injection is not supported , Can not be like asp.net core Put in a like that IConfiguration Object to get the configuration , besides , and asp.net core Of Startup Have the same experience , If you can't find this Startup There are no services or special configurations that need dependency injection , Use it directly Xunit The original XunitTestFrameworkExecutor, If you find it Startup From Startup Configure in the agreed method Host, Registration service and initialization configuration process , Finally using DependencyInjectionTestFrameworkExecutor Carry out our test case.
The source code parsing
The source code uses C#8 Some of the new grammar of , The code is very simple , The following code uses nullable reference types :
DependencyInjectionTestFrameworkSource code
public sealed class DependencyInjectionTestFramework : XunitTestFramework{ public DependencyInjectionTestFramework(IMessageSink messageSink) : base(messageSink) { } protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) { IHost? host = null; try { // obtain Startup example var startup = StartupLoader.CreateStartup(StartupLoader.GetStartupType(assemblyName)); if (startup == null) return new XunitTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink); // establish HostBuilder var hostBuilder = StartupLoader.CreateHostBuilder(startup, assemblyName) ?? new HostBuilder().ConfigureHostConfiguration(builder => builder.AddInMemoryCollection(new Dictionary<string, string> { { HostDefaults.ApplicationKey, assemblyName.Name } })); // call Startup Medium ConfigureHost Method configuration Host StartupLoader.ConfigureHost(hostBuilder, startup); // call Startup Medium ConfigureServices Method register service StartupLoader.ConfigureServices(hostBuilder, startup); // Register default service , structure Host host = hostBuilder.ConfigureServices(services => services .AddSingleton(DiagnosticMessageSink) .TryAddSingleton<ITestOutputHelperAccessor, TestOutputHelperAccessor>()) .Build(); // call Startup Medium Configure Method to initialize StartupLoader.Configure(host.Services, startup); // return testcase executor, Ready to start running test cases return new DependencyInjectionTestFrameworkExecutor(host, null, assemblyName, SourceInformationProvider, DiagnosticMessageSink); } catch (Exception e) { return new DependencyInjectionTestFrameworkExecutor(host, e, assemblyName, SourceInformationProvider, DiagnosticMessageSink); } }}
StarpupLoaderSource code
public static Type? GetStartupType(AssemblyName assemblyName){ var assembly = Assembly.Load(assemblyName); var attr = assembly.GetCustomAttribute<StartupTypeAttribute>(); if (attr == null) return assembly.GetType($"{assemblyName.Name}.Startup"); if (attr.AssemblyName != null) assembly = Assembly.Load(attr.AssemblyName); return assembly.GetType(attr.TypeName) ?? throw new InvalidOperationException($"Can't load type {attr.TypeName} in '{assembly.FullName}'");}public static object? CreateStartup(Type? startupType){ if (startupType == null) return null; var ctors = startupType.GetConstructors(); if (ctors.Length != 1 || ctors[0].GetParameters().Length != 0) throw new InvalidOperationException($"'{startupType.FullName}' must have a single public constructor and the constructor without parameters."); return Activator.CreateInstance(startupType);}public static IHostBuilder? CreateHostBuilder(object startup, AssemblyName assemblyName){ var method = FindMethod(startup.GetType(), nameof(CreateHostBuilder), typeof(IHostBuilder)); if (method == null) return null; var parameters = method.GetParameters(); if (parameters.Length == 0) return (IHostBuilder)method.Invoke(startup, Array.Empty<object>()); if (parameters.Length > 1 || parameters[0].ParameterType != typeof(AssemblyName)) throw new InvalidOperationException($"The '{method.Name}' method of startup type '{startup.GetType().FullName}' must without parameters or have the single 'AssemblyName' parameter."); return (IHostBuilder)method.Invoke(startup, new object[] { assemblyName });}public static void ConfigureHost(IHostBuilder builder, object startup){ var method = FindMethod(startup.GetType(), nameof(ConfigureHost)); if (method == null) return; var parameters = method.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != typeof(IHostBuilder)) throw new InvalidOperationException($"The '{method.Name}' method of startup type '{startup.GetType().FullName}' must have the single 'IHostBuilder' parameter."); method.Invoke(startup, new object[] { builder });}public static void ConfigureServices(IHostBuilder builder, object startup){ var method = FindMethod(startup.GetType(), nameof(ConfigureServices)); if (method == null) return; var parameters = method.GetParameters(); builder.ConfigureServices(parameters.Length switch { 1 when parameters[0].ParameterType == typeof(IServiceCollection) => (.........
版权声明
本文为[Irving the procedural ape]所创,转载请带上原文链接,感谢
边栏推荐
- How to learn technology efficiently
- Summary of the resumption of a 618 promotion project
- 栈-括号的匹配
- Count the frequency of letters in text (case insensitive)
- A detailed explanation of microservice architecture
- How to deal with data leakage and deletion related to business life and death?
- On hiz buffer
- 爆一个VS2015 Update1更新带来的编译BUG【已有解决方案】
- 团灭 LeetCode 股票买卖问题
- supervisor进程管理安装使用
猜你喜欢

一次公交卡被“盗刷”事件带来的思考

什么都2020了,LINQ查询你还在用表达式树

爆一个VS2015 Update1更新带来的编译BUG【已有解决方案】

What kind of technical ability should a programmer who has worked for 1-3 years? How to improve?

14000 word distributed transaction principle analysis, master all of them, are you afraid of being asked in the interview?

laravel8更新之维护模式改进

C language I blog assignment 03

Ac86u KX Online

Big data algorithm - bloon filter

Don't treat exceptions as business logic, which you can't afford
随机推荐
laravel8更新之维护模式改进
Thinkphp6中where条件中字段与字段比较条件的写法
On the concurrency of update operation
【C++学习笔记】C++ 标准库 std::thread 的简单使用,一文搞定还不简单?
The CPU does this without the memory
Exploration and practice of growingio responsive programming
More than 50 object detection datasets from different industries
Web安全(一)---浏览器同源策略
洞察——风格注意力网络(SANet)在任意风格迁移中的应用
Cpp(一) 安装CMake
使用jsDelivr加速你的网站
Annual salary of 900000 programmers is not as good as 3800 civil servants a month? How to choose between stability and high income?
Cpp(四) Boost安装及基本使用 for Mac
微信小程序request报400错误 @RequestBody接收不到
awk实现类sql的join操作
Deep into web workers (1)
Improvement of maintenance mode of laravel8 update
Cpp(三) 什么是CMake
CPP (1) installation of cmake
graph generation model