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 里面整理拷贝而来,中英文混合,将就着看,主要把我的实现代码分享,方便有需要的人。
代码语言:javascript复制 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):
代码语言:javascript复制 settings["DatabaseProvider"] ="SqlConnection";
settings["ConnectionString"] = "Server=localhost;Database=xxx;User Id=sa;Password=xxxxxxx";
settings["TablePrefix"] = "xxx";
代码语言:javascript复制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`.
代码语言:javascript复制 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;
}
使用的例子(先继承基类):
代码语言:javascript复制 [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);
});
}
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/119608.html原文链接:https://javaforall.cn