当前位置:网站首页>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 :
DependencyInjectionTestFramework
Source 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); } }}
StarpupLoader
Source 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]所创,转载请带上原文链接,感谢
边栏推荐
- Git code submission operation, and git push prompt failed to push some refs'xxx '
- The prediction accuracy of the model is as high as 94%! Using machine learning to solve the 200 billion dollar inventory problem perfectly
- 一万四千字分布式事务原理解析,全部掌握你还怕面试被问?
- 计组-总线通信控制之异步串行通信的数据传输
- 低代码 vs 模型驱动,它们之间到底是什么关系?
- High concurrency in ngnix cluster
- AFO记
- Adobe Lightroom / LR 2021 software installation package (with installation tutorial)
- Web安全(四)---XSS攻击
- 某618大促项目的复盘总结
猜你喜欢
某618大促项目的复盘总结
密码学-尚硅谷
See once to understand, graphic single chain table inversion
Improvement of maintenance mode of laravel8 update
What do you think of the most controversial programming ideas?
京淘项目day09
Deep into web workers (1)
laravel8更新之维护模式改进
Analysis of kubernetes service types: from concept to practice
洞察——风格注意力网络(SANet)在任意风格迁移中的应用
随机推荐
WPF personal summary on drawing
Awk implements SQL like join operation
ROS学习---远程启动ROS节点
Code Review Best Practices
Let's talk about the locks in the database
On hiz buffer
来自不同行业领域的50多个对象检测数据集
密码学-尚硅谷
凯撒密码实现
Python image recognition OCR
Improvement of maintenance mode of laravel8 update
awk实现类sql的join操作
Exploration and practice of growingio responsive programming
DOM节点操作
CPP (1) installation of cmake
Do not understand the underlying principle of database index? That's because you don't have a B tree in your heart
Big data algorithm - bloon filter
Analysis of kubernetes service types: from concept to practice
CPP (2) creating CPP project
Thinkphp6中where条件中字段与字段比较条件的写法