سؤال

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.

هل كانت مفيدة؟

المحلول

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top