在 .NET 中执行测试之前清理数据库

Posted

技术标签:

【中文标题】在 .NET 中执行测试之前清理数据库【英文标题】:Clean database before executing a test in .NET 【发布时间】:2013-10-13 08:40:40 【问题描述】:

场景

我们正在开发一组使用应用程序数据库的集成测试。为此,我们已将数据库切换到单独的测试数据库,该数据库仅在集成测试期间使用。

测试数据库在每次测试后通过还原 SQL Server 数据库快照重置为其原始状态。这工作正常,但它让我们不再头疼设置。

问题

是否有任何工具可以在自动化测试之前或之后更轻松地清理数据库?

我们使用 MSTest 作为我们的测试框架,但我愿意接受任何需要不同测试框架才能使数据库清理工具正常工作的建议。

【问题讨论】:

【参考方案1】:

我在使用 NUnit 时遇到了同样的问题,所以我创建了一个实现 ITestAction 的属性(Nunit,在其他测试框架中有相同的结果)方法,包括 BeforeTest 和 AfterTest 我使用 System.Transactions 程序集来存储整个断言此属性后事务中的数据库更改处理(回滚)事务和状态将被重置。 这是关于它的link to my article。

这是属性类:

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;

【讨论】:

【参考方案2】:

经过仔细考虑,我们找到了一个非常适合我们的解决方案。

因此,在我们的单元测试开始时,我们创建了数据库的快照。为此,我们使用 SQL Server 中的快照功能。

然后我们针对这个快照执行测试。

测试完成后,我们再次删除快照。 这使我们的测试数据库保持干净。

注意如果您绝对必须在单元测试中使用数据库,我只会推荐这种工作方式。一般来说,你不应该。我认为在大多数情况下,您应该能够以这样一种方式重构您的代码,从而在执行单元测试时无需将内容存储在数据库中。

【讨论】:

【参考方案3】:

重生也可以使用。

来自 GitHub 存储库中 README.md 文件的描述。 (https://github.com/jbogard/Respawn)

“Respawn 是一个小型实用程序,可帮助将测试数据库重置为干净状态。Respawn 不会在测试结束时删除数据或回滚事务,而是通过智能地从表。”

xUnit、SQL Server 和 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);
        
    

【讨论】:

【参考方案4】:

请查看我正在开发的 Reseed 库以解决这种情况。

该库能够通过在有序表图形上使用TRUNCATE 语句来快速清理数据库,类似于另一个答案中提到的 Respawn。它巧妙地做到了这一点,甚至能够通过禁用约束来处理表和行级别上的依赖循环。

此外,它还可以为您插入测试数据,因此它基本上提供与数据库快照相同的行为。我在快照性能方面遇到了问题,所以最终得到了一个库。

尽管它仍处于积极开发阶段,但我正在将它用于我的一些项目,目前运行良好。

【讨论】:

以上是关于在 .NET 中执行测试之前清理数据库的主要内容,如果未能解决你的问题,请参考以下文章

何时过滤/清理数据:在数据库插入之前还是在显示之前?

在 Rails 3 上使用 Rspec 和 MongoID 清理或重置测试数据库

清理测试数据库,仅使用RSPEC和Capybara运行测试生成的数据

unittest系统如何在一个测试类多个测试用例执行中只初始化和清理一次?

Flyway 没有正确清理数据库,执行了两次迁移文件

手机管理应用研究—— 垃圾清理篇