Orchard Core 中运行带程序上下文的单元测试

2022-07-11 17:06:39 浏览数 (1)

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

0 人点赞