2
votes

I'm a noob with Castle Windsor. I'm building an application that uses Entity Framework 6 and Castle Windsor, with an MSTest Unit Test class. My application has a class in it that implements IWindsorInstaller. My unit test class looks like this:

[TestClass]
public class DatabaseTests {

    static readonly WindsorContainer Container = new WindsorContainer();

    public DatabaseTests() {
        Container.Install( FromAssembly.This() );
    }

    [TestMethod]
    public void FirstTest() {
        // Test statements
    }

    [TestMethod]
    public void SecondTest() {
        // Test statements
    }

    // Other tests
}

There is also an installer class in the unit tests project that looks like this:

public class TestsInstaller : IWindsorInstaller {
    public void Install( IWindsorContainer container, IConfigurationStore store ) {
        container.Install( new RecipeManager.RepositoriesInstaller() );
    }
}

When I go to the Unit Test Session window & try to run all tests, the first one succeeds, and I get this stack trace for the rest:

Unable to create instance of class UnitTests.DatabaseTests. Error: Castle.MicroKernel.ComponentRegistrationException: Component RecipeManager.DAL.CategoryRepository could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.. at Castle.MicroKernel.SubSystems.Naming.DefaultNamingSubSystem.Register(IHandler handler) at Castle.MicroKernel.DefaultKernel.AddCustomComponent(ComponentModel model) at Castle.MicroKernel.DefaultKernel.Register(IRegistration[] registrations) at Castle.Windsor.WindsorContainer.Register(IRegistration[] registrations) at RecipeManager.RepositoriesInstaller.Install(IWindsorContainer container, IConfigurationStore store) in C:\Users\Tony\documents\visual studio 2015\Projects\RecipeManager\ManageRecipes\RepositoriesInstaller.cs:line 10 at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers, DefaultComponentInstaller scope) at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers) at UnitTests.TestsInstaller.Install(IWindsorContainer container, IConfigurationStore store) in C:\Users\Tony\documents\visual studio 2015\Projects\RecipeManager\UnitTests\TestsInstaller.cs:line 8 at Castle.Windsor.Installer.AssemblyInstaller.Install(IWindsorContainer container, IConfigurationStore store) at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers, DefaultComponentInstaller scope) at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers) at UnitTests.DatabaseTests..ctor() in C:\Users\Tony\documents\visual studio 2015\Projects\RecipeManager\UnitTests\DatabaseTests.cs:line 17

If I run the unit tests one at a time, they all succeed. I intend to build lots of tests, so I'd really rather be able to run them all at once. How do I fix this?

2
I'm wondering if using Castle to handle your dependency injection for testing is actually a bad idea. 1) It violates self-documentation principle for unit tests, since dependencies are now hidden, and 2) if you change your dependencies, your code will still compile, potentially leaving code uncovered.gdbj

2 Answers

7
votes

In your test class, create a field.

private WindsorContainer Container;

(replace the existing static field.)

Then, add this to your test class:

[TestInitialize]
public void SetUp()
{
    Container = new WindsorContainer();
    // register your dependencies
}

[TestCleanup]
public void Cleanup()
{
    Container.Dispose();
}

[TestInitialize] runs before every test, [TestCleanup] after every test.
That way you're not reusing the same container for every test and trying to re-register the same dependencies with that container. Before every single test is run you'll be creating a new container. If you need the same dependencies for every test you can register them in Setup(). Or you can register them in the test methods if needed.

1
votes

To upgrade a bit on this answer: I created a Base RepositoryTest class which contained the Windsor Container logic. That class became the root of all Unit Test classes.

public abstract class RepositoryTestBase
{
    private static IWindsorContainer windsorContainer { get; set; }
    private static IMapper mapper { get; set; }

    protected static IWindsorContainer WindsorContainer
    {
        get
        {
            if (windsorContainer == null)
            {
                WindsorContainerManager.ConfigureWindsor(Assembly.GetExecutingAssembly());
                windsorContainer = WindsorContainerManager.Container;
            }
            return windsorContainer;
        }
    }

    protected IMapper Mapper
    {
        get
        {
            if (mapper == null)
            {
                mapper = WindsorContainer.Resolve<IMapper>();
            }
            return mapper;
        }
    }

    public static T GetResolved<T>()
    {
        return WindsorContainer.Resolve<T>();
    }
}

    [TestFixture, Category("UnitTest")]
public class AccountRepositoryTests : RepositoryTestBase
{
    private IAccountRepository accountRepo = GetResolved<IAccountRepository>();
    private IContactRepository contactRepo = GetResolved<IContactRepository>();