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

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

 

 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);
        });
    }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119608.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • powermodule_getsocketopt

    powermodule_getsocketopt严格模式ES6的模块自动采用严格模式,不管你有没有在模块头部加上"usestrict";。严格模式的限制如下变量必须声明后再使用函数的参数不能有同名属性,否则报错不能

    2022年7月30日
    5
  • 梯度下降法及其Python实现

    梯度下降法及其Python实现梯度下降法 gradientdesc 又名最速下降法 steepestdesc 是求解无约束最优化问题最常用的方法 它是一种迭代方法 每一步主要的操作是求解目标函数的梯度向量 将当前位置的负梯度方向作为搜索方向 因为在该方向上目标函数下降最快 这也是最速下降法名称的由来 梯度下降法特点 越接近目标值 步长越小 下降速度越慢 直观上来看如下图所示 这里每一个圈

    2025年6月11日
    2
  • django WEB聊天室项目[通俗易懂]

    django WEB聊天室项目[通俗易懂]bbs系统项目中我们用到的ajax不多,但是在聊天室里用到的全是ajax,所以本项目的主要内容就是:前端使用ajax传输json格式的数据是本节的重点以及前端函数的的使用.http协议的特点是:短链接,服务器无法主动向客户端发送消息.都是客户端请求服务器返回消息.那么问题来了,WEB聊天账户如何从后台获取消息,还要求实时的.有三种方法:1.从上述内容可知,无法实现后端把消息…

    2022年6月15日
    32
  • 如何学习FPGA「建议收藏」

    如何学习FPGA「建议收藏」PS:笔者强烈建议诸位注册一个EETOP的账号,每天签到或者发贴、回贴就有积分了,里面的资源非常丰富,各种软件、资料都能找到。一、入门首先要掌握HDL(HDL=verilog+VHDL)。第一句话是:还没学数电的先学数电。然后你可以选择verilog或者VHDL,有C语言基础的,建议选择VHDL。因为verilog太像C了,很容易混淆,最后你会发现,你花了大量时间…

    2022年5月3日
    79
  • SpringBoot事务配置管理[通俗易懂]

    SpringBoot事务配置管理[通俗易懂]1.事务使用功能场景:由于数据操作在顺序执行的过程中,线上可能有各种无法预知的问题,任何一步操作都有可能发生异常,异常则会导致后续的操作无法完成,此时由于业务逻辑并未正确的完成,所以在之前操作数据库的动作并不可靠,需要在这种情况下进行数据的回滚。事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务未进行操作的状态。事务管理是SpringBoot框架中最为常用的功能之一,我们在实际应用开发时,基本上在service层处理业务逻辑的时候都要加上事

    2022年6月7日
    40
  • js定时跳转网页_js 网页代码

    js定时跳转网页_js 网页代码效果如下:五秒跳完之后,转到百度的页面js代码如下:window.οnlοad=init;functioninit(){window.setTimeout(“tiaozhuan()”,5000);window.setInterval(“shijian()”,1000);//五秒后调用tiaozhuan}functiontiaozhuan(){location.replace(“http://www.baidu.com”);} functionshijian(){ var

    2022年8月12日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号