Question

I'm using an AutoFixture customization to test a repository which access to a SQL Compact DB.

Would be very helpful to me to delete this database as soon as the test is completed. Because the db is created in the customization constructor I think that the best place to delete it is in the dispose method.

The code which I'm thinking is:

internal class ProjectRepositoryCustomization : ICustomization
{
    private readonly String _dbLocation;

    public ProjectRepositoryCustomization()
    {
        var tempDbLocation = Path.Combine(Path.GetTempPath(), "TempDbToDelete");
        if (!Directory.Exists(tempDbLocation))
        {
            Directory.CreateDirectory(tempDbLocation);
        }

        _dbLocation = Path.Combine(tempDbLocation, Guid.NewGuid().ToString("N") + ".sdf");
    }

    public void Customize(IFixture fixture)
    {   
        DataContextConfiguration.database = _dbLocation;

        var dataContextFactory = new BaseDataContextFactory();
        var projRepository = new ProjectRepository(dataContextFactory);
        fixture.Register(() => projRepository);
    }

    public void Dispose()
    {
        if (File.Exists(_dbLocation))
        {
            File.Delete(_dbLocation);
        }
    }
}

Is possible to do something similar?

Was it helpful?

Solution

As @Ruben Bartelink points out in the comments, it is possible. However, I would recommend a different approach and here's why.

Managing the lifetime of objects is something you would normally expect to be able to do with an IoC container. AutoFixture, however, even though it may look like an IoC container, it's really not meant to be one:

AutoFixture shares a lot of similarities with DI Containers. It supports auto-wiring and it can be configured to create instances in lots of interesting ways. However, since the focus is different, it does some things better and some things not as well as a DI Container.

AutoFixture's main goal is to make it easy to create anonymous test data within some configurable bounds. Its API is focused on allowing the programmer to customize how the test data is generated but not how long it will live, since it's assumed to only be consumed within the context of a test:

AutoFixture is weaker when it comes to lifetime management. A Fixture is never expected to exist for more than a single test case, so it makes no sense to model any other lifestyle than Transient and Singleton. [...] It doesn't have to, because it's not a DI Container.

Test frameworks, on the other hand, are pretty good at managing the lifetime of test fixtures. Since what you're describing is typically part of managing the context for an integration test, I would run it before and after all the tests within the fixture are executed.

For example:

[TestFixture]
public class WithDatabaseContext
{
    private string dbLocation;
    private BaseDataContextFactory dataContextFactory

    protected BaseDataContextFactory DataContextFactory
    {
        get { return this.dataContextFactory; }
    }

    [TestFixtureSetUp]
    public void FixtureInit()
    {
        // Initialize dbLocation
        // Initialize dataContextFactory
    }

    [TestFixtureTearDown]
    public void FixtureDispose()
    {
        // Delete file at dbLocation
    } 
}

Your test could then inherit the context and use it to configure AutoFixture:

[TestFixture]
public void SomeTest : WithDatabaseContext
{
    private IFixture fixture;

    [SetUp]
    public void Init()
    {
        this.fixture = new Fixture();
        this.fixture.Register(
            () => new ProjectRepository(base.DataContextFactory));
    }

    [Test]
    public void Doing_something_should_return_something_else()
    {
        // ...
    }
}

In this case, leveraging the test framework in order to manage the lifetime of the temporary database clearly communicates its boundaries within the context of the tests. Hiding it inside an AutoFixture customization, in my opinion, would make it far less obvious and, arguably, harder to use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top