Technique for using AutoFixture to integration test an application using Castle Windsor
Asked Answered
C

1

6

I'm new to AutoFixture, so I don't know if the following idea is going to make sense or be a reasonable thing to do. I've got an application that I'm in charge of integration testing, and it makes heavy use of Castle Windsor. To simplify dependency management and make my tests more like the application code, I've been building the Windsor container in my test initialize method and the using container.Resolve to instantiate the code I'm testing. I'd like to move away from that approach since it has limited my flexibility in certain situations.

What I'd like to do is have tests that look something like this:

[Theory]
[Dependency]
public void TestWithDependencies(IThing thing)
{
    thing.Hello();
}

To make this happen, I can do the following:

public sealed class DependencyAttribute : AutoDataAttribute
{
    public DependencyAttribute()
        : base(new Fixture().Customize(new WindsorCustomization()))
    {
    }
}

public class WindsorCustomization : ICustomization
{
    public WindsorCustomization()
    {
        // build container here using SUT installers
    }

    public void Customize(IFixture fixture)
    {
        fixture.Inject<IThing>(new Thing());
    }
}

Doing this does work, but what I'd like to avoid is needing to copy every interface to implementation mapping from the Windsor container into the AutoFixture IFixture.

Calculous answered 14/8, 2012 at 18:2 Comment(2)
Welp! I just took a look at the code for AutoMoq and saw exactly how to do what I want to do. I can post the code in an answer if anybody's interested.Calculous
Yes, that's pretty close to how AutoMoq works as well :)Woodpecker
W
6

You should be able to do something like this:

public class WindsorCustomization : ICustomization
{
    private readonly IWindsorContainer container;

    public WindsorCustomization()
    {
        // build this.container here using SUT installers
    }

    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(new WindsorAdapter(this.container));
    }
}

public WindsorAdapter : ISpecimenBuilder
{
    private readonly IWindsorContainer container;

    public WindsorAdapter(IWindsorContainer container)
    {
        this.container = container;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as Type;
        if (t == null || !this.container.Kernel.HasComponent(t))
            return new NoSpecimen(request);

        return this.container.Resolve(t);                
    }
}

The WindsorAdapter sits in the Customizations collection, which is fairly early in AutoFixture's Tree of Responsibility, so it gets a chance to handle every (or most) incoming requests. If the request is a Type instance and the WindsorContainer has a component for that type, the adapter delegates the work of resolving the type to the container.

Otherwise, it returns a NoSpecimen instance, which is basically AutoFixture's way of signaling that this particular ISpecimenBuilder couldn't handle the request. Some other component in the AutoFixture Tree of Responsibility then gets the chance to handle the request.

Woodpecker answered 14/8, 2012 at 19:1 Comment(2)
Yep, that's exactly what I did. The exciting part about this is that since I'm testing code that's only 1/3 implemented, I should be able to use AutoMoq to stand in for the code that doesn't exist and still test the code that does exist. Great library!Calculous
Yes, you just need to make sure that the AutoMoqCustomization comes last/later: blog.ploeh.dk/2012/07/31/…Woodpecker

© 2022 - 2024 — McMap. All rights reserved.