当前位置:网站首页>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]所创,转载请带上原文链接,感谢
边栏推荐
- Thinkphp6中where条件中字段与字段比较条件的写法
- Practice of Xiaoxiong school development board: real equipment access of smart street lamp sandbox experiment
- On the coverage technology and best practice of go code
- The instanceof operator in ecmascript7 specification
- See once to understand, graphic single chain table inversion
- Kylin on kubernetes' practice on eBay
- 京淘项目day09
- In the age of screen reading, we suffer from attention deficit syndrome
- Let's talk about the locks in the database
- 动态规划——用二进制表示集合的状态压缩DP
猜你喜欢
工作1-3年的程序员,应该具备怎么样的技术能力?该如何提升?
京淘项目day09
洞察——风格注意力网络(SANet)在任意风格迁移中的应用
Go之发送钉钉和邮箱
WPF 关于绘图个人总结
不懂数据库索引的底层原理?那是因为你心里没点b树
Git code submission operation, and git push prompt failed to push some refs'xxx '
laravel8更新之维护模式改进
来自不同行业领域的50多个对象检测数据集
Three steps, one pit, five steps and one thunder, how to lead the technical team under the rapid growth?
随机推荐
Python image recognition OCR
Improvement of maintenance mode of laravel8 update
Don't treat exceptions as business logic, which you can't afford
How to deal with data leakage and deletion related to business life and death?
Everything is 2020, LINQ query you are still using expression tree
In the age of screen reading, we suffer from attention deficit syndrome
Reflection on a case of bus card being stolen and swiped
三步一坑五步一雷,高速成长下的技术团队怎么带?
当 TiDB 与 Flink 相结合:高效、易用的实时数仓
云计算之路-出海记:整一台 aws 免费云服务器
Adobe media encoder /Me 2021软件安装包(附安装教程)
Recommend suicide, openai warns: gpt-3 is too risky for medical purposes
Cpp(二) 创建Cpp工程
WPF 关于绘图个人总结
Jingtao project day09
What is the relationship between low code vs model driven?
Implementation of multi GPU distributed training with horovod in Amazon sagemaker pipeline mode
尾-递
[random talk] the goal and way of software design
Web Security (4) -- XSS attack