您可以在单元测试项目中使用 Visual Studio 数据库项目来为功能测试设置空数据库吗?

Can you use a Visual Studio Database Project in a Unit Test Project to setup a empty database for a functional test?

多年来,我们一直使用以下代码在基础 class 中设置数据库,以便对我们的 DAL 进行功能测试,这对我们来说效果非常好。

/// <summary>
/// Initializes the test class by creating the integration database.
/// </summary>
[TestInitialize]
public virtual void TestInitialize()
{
    DataContext = new DataContext(ConnectionString);

    CleanupPreviousTestRunDatabases();

    if (DataContext.Database.Exists())
    {
        DataContext.Database.Delete();
    }

    DataContext.Database.Create();
    DataContext.Database.ExecuteSqlCommand(String.Format(Strings.CreateLoginCommand, DatabaseUserName, DatabasePassword));
    DataContext.Database.ExecuteSqlCommand(String.Format("CREATE USER {0} FOR LOGIN {0}", DatabaseUserName));
    DataContext.Database.ExecuteSqlCommand(String.Format("EXEC sp_addrolemember 'db_owner', '{0}'", DatabaseUserName));
}

但是,使用 Entity Framework 不会设置数据库的所有组件,我们希望找出我们的 EF DAL 模型与实际数据库之间的差异。

我们使用 SSDT 工具/Visual Studio 数据库项目来完成我们所有的数据库工作,我知道您可以编写 SQL 单元测试,在那些 SQL 单元测试中,我已经看到了基于数据库项目本身设置和创建数据库的能力。这是我想做的,但是来自我们的其他功能测试库。

我可以参考这些库并编写一些设置代码,但我正在寻找的是:

a) 如何提供用于部署的数据库项目?

b) 如何在代码中指定连接字符串而不是 app.config,例如使用 localdb 而不是动态命名的数据库?

namespace Product.Data.Tests
{
    using Microsoft.Data.Tools.Schema.Sql.UnitTesting;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class FunctionalTest
    {
        [TestInitialize]
        public virtual void TestInitialize()
        {
            SqlDatabaseTestClass.TestService.DeployDatabaseProject();
            SqlDatabaseTestClass.TestService.GenerateData();
        }
    }
}

SQL 单元测试项目中的 app.config 不包含对用于创建它的原始数据库项目的任何引用,反编译一些测试代码并查看它是如何工作的,我没有看到任何迹象。是否假设解决方案中只有一个数据库项目?

我认为你的过程有点过于复杂(如果我理解正确的话我可能没有!)。

我在 ssdt 中做的单元测试是:

  • 构建解决方案
  • 将我需要的每个 dacpac 部署到我的开发实例
  • 运行 测试

部署项目有几种方法,您可以:

  • 为每个项目创建一个 "Publish Profile" 并且 运行
  • 右键单击项目并选择发布
  • 使用 powershell 脚本(或在测试初始化​​的代码中执行)发布 dacpac。

部署后 运行 您的测试,通过代码或脚本发布 dacpac(项目)非常简单,您可以:

如果您自己控制发布,那么它会给您更多的控制权 加上 当您使用它进行部署时,您正在测试将在其他环境中使用的相同部署系统(假设您使用 dacpac 进行部署)。

编辑

根据@Ed Elliott 发布的链接的一些指导,我能够做到这一点。您需要添加 Microsoft.SqlServer.Dac 作为来自 C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC0\Microsoft.SqlServer.Dac.dll (Visual Studio 2015) 的程序集引用。它是 SSDT 工具的一部分,所以我确信早期版本的路径可能不同。

[TestClass]
public class DatabaseTest
{
    protected string DatabaseConnectionString = $@"Data Source=(localdb)\v11.0; Integrated Security=True";
    protected DatabaseContext DatabaseContext;
    protected string DatabaseName = $"UnitTestDB_{Guid.NewGuid().ToString("N").ToUpper()}";

    public TestContext TestContext { get; set; }

    [TestInitialize]
    public virtual void TestInitialize()
    {
        var instance = new DacServices(DatabaseConnectionString);
        var path     = Path.GetFullPath(Path.Combine(TestContext.TestDir, 
                                        @"..\..\..\Build\Database\Database.dacpac"));

        using (var dacpac = DacPackage.Load(path))
        {
            instance.Deploy(dacpac, DatabaseName);
        }

        DatabaseContext = new DatabaseContext(DatabaseConnectionString);
    }

    [TestCleanup]
    public virtual void TestCleanup()
    {
        DeleteDatabase(DatabaseName);
    }
}

然后如何将它用于单元测试项目中的功能测试。

[TestClass]
public class CustomerTypeTests : DatabaseTest
{
    private CustomerType customerType;

    [TestInitialize]
    public override void TestInitialize()
    {
        base.TestInitialize();

        customerType = new CustomerType
                       {
                           Name = "Customer Type"
                       };
    }

    [TestMethod]
    public void AddOrUpdateCustomerType_ThrowExceptionIfNameIsNull()
    {
        ExceptionAssert.Throws<ArgumentNullException>(() => DatabaseContext.AddOrUpdateCustomerType(customerType));
    }
}

请注意,您还应该设置 Build Dependencies,以便您的单元测试项目依赖于数据库项目,确保首先构建它并生成正确的 dacpac 文件。

这为我们解决的问题是,它是否为我们提供了一个真正的数据库,而不是仅基于 Entity Framework 模型的数据库,后者缺少很多 SQL 构造(可以预期) ,尤其是默认约束、索引和数据库的其他重要元素。在我们的 DAL 层,这对我们来说是必不可少的。