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

时间:2016-05-13 01:21:08

标签: c# entity-framework visual-studio unit-testing sql-server-data-tools

多年来,我们使用以下代码在基类中为我们的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不包含对用于创建它的原始数据库项目的任何引用,并且反编译一些测试代码并查看它是如何工作的,我不会&#39;看到任何迹象。是否假设解决方案中只有一个数据库项目?

2 个答案:

答案 0 :(得分:8)

根据@Ed Elliott发布的链接的指示,我能够实现这一目标。您需要从Microsoft.SqlServer.Dac(Visual Studio 2015)添加C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120\Microsoft.SqlServer.Dac.dll作为程序集引用。它是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文件。

这为我们解决的是,这给了我们一个真正的数据库,而不仅仅是基于实体框架的模型,它缺少相当多的SQL结构(预期),特别是默认约束,索引和其他重要元素一个数据库。在我们的DAL层,这对我们来说至关重要。

答案 1 :(得分:5)

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

我在ssdt中进行单元测试的目的是:

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

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

  • 创建&#34;发布个人资料&#34;对于每个项目并运行
  • 右键单击该项目并选择发布
  • 使用powershell脚本(或在测试初始化​​的代码中执行此操作)来发布dacpac。

一旦部署完成运行测试,从代码或脚本中发布dacpac(项目)非常简单,你可以:

如果您自己控制发布,那么当您使用它时,它会为您提供更多控制 plus ,您正在测试将在其他环境中使用的相同部署系统(假设您使用dacpac&# 39;要部署)。