Testing Castle windsor Component with PerWebRequest lifestyle
Asked Answered
C

4

19

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

Cyndycynera answered 25/4, 2011 at 18:20 Comment(1)
I asked a similar question yesterday at #5772997Sheer
F
21

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;
}
Fenderson answered 25/4, 2011 at 19:19 Comment(3)
Mauricio, many thanks for your answer, I've scratched my head with this one for a while. Kind of new with windsor.Cyndycynera
Thanks for the idea. Needed to unittest the override functionality as expected. Done that for LifestyleSingleton by resolving same IType twice and checking objects are same.Marcellemarcellina
It works but I had to check for lifestyle PerWebRequest instead of Undefined. Perhaps it is a change in behavior since your answer was posted years ago. So the condition becomes : if (model.LifestyleType == Castle.Core.LifestyleType.PerWebRequest). Thank you !Bernadinebernadotte
M
1

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);
    }
}
Michaelmas answered 19/6, 2019 at 6:51 Comment(0)
S
1

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;
Supercool answered 23/4, 2020 at 19:37 Comment(0)
B
0

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")
Breda answered 12/6, 2019 at 11:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.