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

 

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • RAID技术全解图解-RAID0、RAID1、RAID5、RAID100

    图文并茂RAID技术全解–RAID0、RAID1、RAID5、RAID100……  RAID技术相信大家都有接触过,尤其是服务器运维人员,RAID概念很多,有时候会概念混淆。这篇文章为网络转载,写得相当不错,它对RAID技术的概念特征、基本原理、关键技术、各种等级和发展现状进行了全面的阐述,并为用户如何进行应用选择提供了基本原则,对于初学者应该有很大的帮助。一、RAID概…

  • 哈希冲突原因「建议收藏」

    哈希冲突原因「建议收藏」哈希计算就是努力的把比较大的数据存放到相对较小的空间中。最常见的哈希算法是取模法。下面简单讲讲取模法的计算过程。比如:数组的长度是5。这时有一个数据是6。那么如何把这个6存放到长度只有5的数组中呢。按照取模法,计算6%5,结果是1,那么就把6放到数组下标是1的位置。那么,7就应该放到2这个位置。到此位置,哈斯冲突还没有出现。这时,有个数据是11,按照取模法,11%5=1,也等于1。那

  • hibernate二级缓存(二)二级缓存实现原理简单剖析

    hibernate二级缓存(二)二级缓存实现原理简单剖析hibernate二级缓存(一)二级缓存的实现原理在前面我们将过hibernate二级缓存类似于一个插件,将缓存的具体实现分离,缓存的具体实现是通过hibernate.cache.region.factory_class参数配置指定。1.hibernate二级缓存结构hibernate二级缓存涉及到如下几个重要的接口:RegionFactoryDomainDataRegionEnt…

  • 基于MAX31865的温度控制系统

    基于MAX31865的温度控制系统系统介绍这是之前写的关于MAX31865测温相关的文章,本次在此基础上又实现了一些新功能。总结——STM32F103C8T6通过MAX31865读取PT100电阻值STM32控制max31865,利用pt100测温度,利用0.96OLED液晶显示屏显示温度值。温度过高控制风扇开启,温度过低控制加热膜加热。后续需要增加温度过高或过低蜂鸣器响且液晶有提示报警类型。系统组成STM32F103C8T6小系统板单片机核心板STM32开发板学习板实验板(升级版)MAX31865RTD铂电阻温度检测器

  • python如何读取sql文件_sql数据库常用命令

    python如何读取sql文件_sql数据库常用命令基本思路:①读sql文件,整理出sql语句;②执行sql语句。简单代码如下:#db_cursor→由db_cursor()创建,sql_file→sql文件defread_SQL(self,db_cursor,sql_file):#打开文件fpfp=open(sql_file,encoding=’utf8′)#读文件file=fp.readlines()#sql语句集合(

  • 转载:QT版本系列介绍[通俗易懂]

    转载:QT版本系列介绍[通俗易懂]
    一、Qt简介
    Qt工具包是一个跨平台的C++开发工具。Qt被主要用在了KDE桌面环境的开发中。它是挪威Trolltech公司的产品,2008年6月17日被芬兰的诺基亚(Nokia)公司收购,以增强该公司在跨平台软件研发方面的实力。
    使用Qt开发的软件,可以在任何支援的平台上编译与执行,而不需要修改源代码。可以实现本平台的图形界面风格,也可实现其它平台的图形界面风格。比如您可以在MicrosoftWindows平台下编译出具有苹果公司MacOS图形界面风格的应用程序。

发表回复

您的电子邮箱地址不会被公开。

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