简体   繁体   中英

Clean database before executing a test in .NET

Scenario

We're working on a set of integration tests that make use of the application database. For this purpose we already switched the database to a separate test database that's only used during integration tests.

The test database is reset after each test to it's original state, by restoring a SQL Server database snapshot. This works okay, but it's given us quit a headache to set up.

Question

Are there any tools that make cleaning up a database before or after an automated test easier?

We are using MSTest as our test framework, but I'm open to any suggestions that require a different test framework for the database cleaning tool to work.

After careful consideration we found a solution that works great for us.

So at the beginning of our unit-test we create a snapshot of the database. We use the snapshotting features in SQL server for that.

We then execute the tests against this snapshot.

After the test is finished we remove the snapshot again. This keeps our test database clean.

Note I would only recommend this way of working if you absolutely have to use a database in your unit-tests. In general you shouldn't. I think in most cases you should be able to refactor your code in such a way that you don't need to store stuff in a database when executing unit-tests.

I had the same problem I was using NUnit so I create an attribute which implements ITestAction (Nunit, there is something for the same result in other test frameworks) methods including BeforeTest and AfterTest And I used System.Transactions assembly to store whole database changes in a transaction after assertion this attribute dispose(rollback) the transaction and state would be reset. here is the link to my article about it.

this is the attribute class:

public class ResetDatabse : Attribute, ITestAction
{

    private TransactionScope _transactionScope;
    public void BeforeTest(ITest test)
    {
        _transactionScope = new TransactionScope();
    }

    public void AfterTest(ITest test)
    {
        _transactionScope.Dispose();
    }

    public ActionTargets Targets => ActionTargets.Test;
}

Respawn can also be used.

The description from the README.md file in the GitHub repo. ( https://github.com/jbogard/Respawn )

"Respawn is a small utility to help in resetting test databases to a clean state. Instead of deleting data at the end of a test or rolling back a transaction, Respawn resets the database back to a clean checkpoint by intelligently deleting data from tables."

Example with xUnit, SQL Server and Dapper.

using System.Data.Common;
using System.Threading.Tasks;
using Dapper;
using Microsoft.Data.SqlClient;
using Respawn;
using Xunit;

namespace TestRespawn
{
    public class ResetSqlServerFixture : IAsyncLifetime
    {
        private readonly Checkpoint _checkpoint;
        private readonly string _connectionString;

        public ResetSqlServerFixture(string connectionString)
        {
            _connectionString = connectionString;

            Connection = new SqlConnection(connectionString);

            _checkpoint = new Checkpoint();
        }

        public DbConnection Connection { get; }

        public virtual Task DisposeAsync() => _checkpoint.Reset(_connectionString);

        public virtual Task InitializeAsync() => Task.CompletedTask;
    }

    // Usage
    public class ExampleTests : ResetSqlServerFixture
    {
        public ExampleTests()
            : base(@"Server=(localdb)\MSSQLLocalDB;Integrated Security=true;")
        {
        }

        [Fact]
        public async Task GetVersion()
        {
            // Arrange
            var sqlQuery = "SELECT @@Version";

            // Action
            var version = await this.Connection.ExecuteScalarAsync(sqlQuery) as string;

            // Assert
            Assert.Contains("Microsoft", version);
        }
    }
}

Please take a look at Reseed library I'm developing to address that scenario.

The library is able to clean database in a fast way by using TRUNCATE statements on the ordered tables graph similarly to the Respawn mentioned in another answer. It does this smartly and is even able to take care of dependencies loops on both tables and rows levels by disabling constraints.

Moreover it's able to insert test data for you, so it basically provides the same behaviour as database snapshots. I had issues with snapshots performance, so ended up with a library.

Even though it's still in active development phase, I'm using it for a few my projects, works well so far.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM