- A+
Orchard Core 带有很多单元测试,使用 Xunit 单元测试框架,除了简单的直接调用待测试的方法,有一些复杂的测试是需要上下文的,甚至需要 Application 程序启动起来,Orchard Core 的例子中有一个基于 HTTP 的 Application 测试,但是其测试都是通过调用 HTTP API 执行的,测试 Controller 挺方便,但是测试 Service 等就麻烦了,而且测试往往是需要调用内部的一些方法的,所以 HTTP API 测试适用范围有限。
`WebApplicationFactory` can only test by http method, could not direct call Application's component, like do some Session.Query() then direct call some method to do a complex test.
所以自己做了个能够启动 Application 且在 Application 上下文内执行测试的单元测试基类和辅助方法。使用方便,继承即可使用,然后你就可以像在 Orchard Core 内部写代码一样,去调用各种 Service、Query 进行测试啦。
由于是从我给 Orchard Core 团队提的 issue 里面整理拷贝而来,中英文混合,将就着看,主要把我的实现代码分享,方便有需要的人。
public class AppTestBase<TFixture> : IClassFixture<TFixture> where TFixture : class, IApplicationStartupFixture
{ public readonly TFixture Application; public AppTestBase(TFixture application) { this.Application = application; } protected T GetService<T>() where T : class { return this.Application.ServiceProvider.GetService<T>(); } protected T GetRequiredService<T>() where T : class { return this.Application.ServiceProvider.GetRequiredService<T>(); } protected async Task RunInShellScopeAsync(Func<ShellScope, Task> execute) { var shellContextFactory = GetRequiredService<IShellContextFactory>(); IShellHost shellHost = GetRequiredService<IShellHost>(); using (var shell = await shellContextFactory.CreateDefaultShellContext()) using (var shellScope = shell.CreateScope()) { var httpContextAccessor = shellScope.ServiceProvider.GetService<IHttpContextAccessor>(); httpContextAccessor.HttpContext = shellScope.ShellContext.CreateHttpContext(); await shellScope.UsingAsync(execute); } } protected T CreateController<T>(ShellScope shellScope, HttpContext httpContext) { var controllerActivatorProvider = shellScope.ServiceProvider.GetService<IControllerActivatorProvider>(); var controllerContext = new ControllerContext() { HttpContext = httpContext, }; var controllerObj = (T) controllerActivatorProvider.CreateActivator( new ControllerActionDescriptor() {ControllerTypeInfo = (TypeInfo) typeof(T),}) .Invoke(controllerContext); return controllerObj; } }
add database setting in ShellSettings (required):
settings["DatabaseProvider"] ="SqlConnection"; settings["ConnectionString"] = "Server=localhost;Database=xxx;User Id=sa;Password=xxxxxxx"; settings["TablePrefix"] = "xxx";
public static class TestShellContextFactoryExtensions { internal static Task<ShellContext> CreateDefaultShellContext(this IShellContextFactory shellContextFactory) { var settings = new ShellSettings() { Name = ShellHelper.DefaultShellName, State = TenantState.Running }; settings["DatabaseProvider"] ="SqlConnection"; settings["ConnectionString"] = "Server=localhost;Database=xxx;User Id=sa;Password=xxxxxxx"; settings["TablePrefix"] = "xxx"; return shellContextFactory.CreateDescribedContextAsync(settings, new ShellDescriptor() { Features = new List<ShellFeature>() { new ShellFeature("Application.Default"), new ShellFeature("OrchardCore.Setup"), new ShellFeature("Operational"), }, Parameters = new List<ShellParameter>(), }); // return shellContextFactory.CreateShellContextAsync(settings); } }
An helper to create `HttpContext`, and set set `shell.RequestServices` to `HttpContext`.
public static HttpContext CreateHttpContext(this ShellContext shell) { var settings = shell.Settings; var context = new DefaultHttpContext(); // set shell.RequestServices to context context.RequestServices = shell.ServiceProvider; OrchardCore.Modules.HttpContextExtensions.UseShellScopeServices(context); var urlHost = settings.RequestUrlHost?.Split('/', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); context.Request.Host = new HostString(urlHost ?? "localhost"); if (!String.IsNullOrWhiteSpace(settings.RequestUrlPrefix)) { context.Request.PathBase = "/" + settings.RequestUrlPrefix; } context.Request.Path = "/"; context.Items["IsBackground"] = true; context.Features.Set(new ShellContextFeature { ShellContext = shell, OriginalPathBase = String.Empty, OriginalPath = "/" }); return context; }
使用的例子(先继承基类):
[Fact] public async Task InAppRuntimeTest() { await RunInShellScopeAsync(async shellScope => { var session = shellScope.ServiceProvider.GetService<ISession>(); Assert.NotNull(session); var controllerObj = CreateController<XxxxxController>(shellScope, shellScope.ShellContext.CreateHttpContext()); var result = await controllerObj.Index(new XxxxModel(){}); Assert.NotNull(result); }); }
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫