使用 PerWebRequest 生活方式测试 Castle Windsor 组件

发布于 2024-11-03 20:17:31 字数 557 浏览 6 评论 0原文

我正在尝试对温莎城堡进行一些测试,在我的一项测试中,我想检查温莎安装程序,因此我检查容器是否可以根据其接口解析我的组件。

到目前为止,一切都很好,当组件在其安装程序中具有 PerWebRequest 生活方式时,问题就开始了,一开始它抱怨 HttpContext.Current 为空,解决了在测试设置中创建假上下文的问题,我现在在 nunit 中遇到了这个异常test

System.Exception:看起来您忘记注册http模块Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule 将 '' 添加到 web.config 的部分。如果您在集成模式下运行 IIS7,则需要将其添加到

当我从 NUnit 运行此程序时,我如何在温莎中注册模块或类以使其正常工作,或者如何进行模拟下的部分,如下所示test 并不是真正的 Web 请求,只是检查容器是否解析类型。

如果我在真实的 Web 请求之外使用此组件进行任何集成测试,也会发生同样的事情,有什么方法可以使这项工作正常工作或真正模拟 Web 请求,以便可以运行此测试?

提前火车

Fer

I'm trying to do some testing with castle windsor involved, in one of my tests I want to check the windsor installers, so I check that the container can resolve my components given its interface.

So far, so good, the problem starts when the component has PerWebRequest lifestyle in its installer, at first it complained about HttpContext.Current is null, having that one solved creating a fake Context in test setup I'm now having this exception in nunit test

System.Exception : Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule
Add '' to the section on your web.config. If you're running IIS7 in Integrated Mode you will need to add it to section under

As I'm running this from NUnit, how I can register the module or class in windsor so it works, or how can be mocked, as in this test is not really a web request, just checking that the container resolve the type.

And also this same thing will happen if I make any integration tests with this component outside a real webrequest, is there any way to make this work or really mock a web request so this tests can be run?

Tranks in advance

Fer

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦初启 2024-11-10 20:17:31

在您的测试中,您可以订阅 ComponentModelCreated 事件并将每个 Web 请求组件的生活方式更改为其他内容。 (示例)。

如果您正在编写具有单个请求范围的集成测试,则应该使用单例。

如果您正在编写跨越多个请求的集成测试,则可以使用 上下文生活方式来模拟请求的范围。

编辑:包括示例中的代码(不再可用):

container.Kernel.ComponentModelCreated += Kernel_ComponentModelCreated;

...

void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
    if (model.LifestyleType == LifestyleType.Undefined)
        model.LifestyleType = LifestyleType.Transient;
}

In your test you could subscribe to the ComponentModelCreated event and change the lifestyle of your per-web-request components to something else. (example).

If you're writing an integration test with the scope of a single request, singleton should do.

If you're writing an integration test that spans multiple requests, you could use a contextual lifestyle to simulate the scope of requests.

Edit: including code from example (which is no longer available):

container.Kernel.ComponentModelCreated += Kernel_ComponentModelCreated;

void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
    if (model.LifestyleType == LifestyleType.Undefined)
        model.LifestyleType = LifestyleType.Transient;
}
场罚期间 2024-11-10 20:17:31

从 Windsor 版本 5 开始,如果您使用的是 Castle.Facilities.AspNet.SystemWeb.WebRequestScopeAccessor,则接受的答案不起作用,因为 PerWebRequest 生活方式已经是一种范围生活方式。

我通过将 ComponentModelCreated 委托更改为以下内容来使其工作:

void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
    const string CastleScopeAccessorType = "castle.scope-accessor-type";

    if (model.ExtendedProperties.Contains(CastleScopeAccessorType))
    {
        model.ExtendedProperties.Remove(CastleScopeAccessorType);
    }
}

From version 5 of Windsor the accepted answer doesn't work if you are using Castle.Facilities.AspNet.SystemWeb.WebRequestScopeAccessor because the PerWebRequest lifestyle is already a scoped lifestyle.

I got it to work by changing the the ComponentModelCreated delegate to the following:

void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
    const string CastleScopeAccessorType = "castle.scope-accessor-type";

    if (model.ExtendedProperties.Contains(CastleScopeAccessorType))
    {
        model.ExtendedProperties.Remove(CastleScopeAccessorType);
    }
}
甜嗑 2024-11-10 20:17:31

我最终实现了这个扩展。 ATTN:必须使用PerWebRequest生活方式加载组件之前调用:

public static class WindsorContainerExtensions
{
    public static IWindsorContainer OverridePerWebRequestLifestyle(this IWindsorContainer container)
    {
        container.Kernel.ComponentModelCreated += model =>
        {
            if (model.IsPerWebRequestLifestyle())
            {
                model.LifestyleType = LifestyleType.Transient;
            }
        };

        return container;
    }

    private static bool IsPerWebRequestLifestyle(this ComponentModel model)
    {
        return model.LifestyleType == LifestyleType.Scoped
            && model.HasAccessorType(typeof(WebRequestScopeAccessor));
    }

    private static bool HasAccessorType(this ComponentModel model, Type type)
        => model.HasExtendedProperty("castle.scope-accessor-type", type);

    private static bool HasExtendedProperty<T>(this ComponentModel model, object key, T expected)
    {
        return model.ExtendedProperties[key] is T actual
            && EqualityComparer<T>.Default.Equals(actual, expected);
    }
}

需要这些导入:

using System;
using System.Collections.Generic;
using Castle.Core;
using Castle.Facilities.AspNet.SystemWeb;
using Castle.Windsor;

I ended up implementing this extension. ATTN: Must call before loading components with the PerWebRequest lifestyle:

public static class WindsorContainerExtensions
{
    public static IWindsorContainer OverridePerWebRequestLifestyle(this IWindsorContainer container)
    {
        container.Kernel.ComponentModelCreated += model =>
        {
            if (model.IsPerWebRequestLifestyle())
            {
                model.LifestyleType = LifestyleType.Transient;
            }
        };

        return container;
    }

    private static bool IsPerWebRequestLifestyle(this ComponentModel model)
    {
        return model.LifestyleType == LifestyleType.Scoped
            && model.HasAccessorType(typeof(WebRequestScopeAccessor));
    }

    private static bool HasAccessorType(this ComponentModel model, Type type)
        => model.HasExtendedProperty("castle.scope-accessor-type", type);

    private static bool HasExtendedProperty<T>(this ComponentModel model, object key, T expected)
    {
        return model.ExtendedProperties[key] is T actual
            && EqualityComparer<T>.Default.Equals(actual, expected);
    }
}

Requires these imports:

using System;
using System.Collections.Generic;
using Castle.Core;
using Castle.Facilities.AspNet.SystemWeb;
using Castle.Windsor;
浅听莫相离 2024-11-10 20:17:31

如果您还想检查范围类型是否是每个网络请求,您也可以这样做

var isPerWebRequestScope = JsonConvert.SerializeObject(model.ExtendedProperties).Contains("Castle.Facilities.AspNet.SystemWeb.WebRequestScopeAccessor")

If you also want to check if the type of scope is per web request you could also do this

var isPerWebRequestScope = JsonConvert.SerializeObject(model.ExtendedProperties).Contains("Castle.Facilities.AspNet.SystemWeb.WebRequestScopeAccessor")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文