您可以在单元测试项目中使用 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(项目)非常简单,您可以:
- 致电sqlpackage.exe为您完成
- 使用 dacfx api 进行部署 (http://blogs.msmvps.com/deborahk/deploying-a-dacpac-with-dacfx-api/)
如果您自己控制发布,那么它会给您更多的控制权 加上 当您使用它进行部署时,您正在测试将在其他环境中使用的相同部署系统(假设您使用 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 层,这对我们来说是必不可少的。
多年来,我们一直使用以下代码在基础 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(项目)非常简单,您可以:
- 致电sqlpackage.exe为您完成
- 使用 dacfx api 进行部署 (http://blogs.msmvps.com/deborahk/deploying-a-dacpac-with-dacfx-api/)
如果您自己控制发布,那么它会给您更多的控制权 加上 当您使用它进行部署时,您正在测试将在其他环境中使用的相同部署系统(假设您使用 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 层,这对我们来说是必不可少的。