我已经配置了一个.mdf
文件以及一个localdb连接字符串,用于单元测试,如下所示:
<connectionStrings>
<add name="TestData" providerName="System.Data.SqlClient" connectionString="Data Source=(localdb)\v11.0; AttachDBFilename='|DataDirectory|\TestData.mdf'; Integrated Security=True"/>
</connectionStrings>
一旦我为我的测试正确配置了部署文件,这就可以很好地工作:.mdf的副本附加到LocalDB的默认实例,SqlClient
连接到它而没有一丝配置。它只是有效。
但我如何在事后清理?在我的本地方框中,我可以定期使用SSMS手动分离旧的测试数据库,但在CI服务器上,显然最好让单元测试自行清理。
是否有类似的自动方式导致localdb数据库与实例分离?
答案 0 :(得分:4)
这就是我删除localDB数据库的方法。我不喜欢的是.mdf也被删除了。我通过先将它复制到tem目录并使用副本创建数据库来克服这个问题。
var sc = new Microsoft.SqlServer.Management.Common.ServerConnection(your localDB SqlConnection here);
var server = new Microsoft.SqlServer.Management.Smo.Server(sc);
server.KillDatabase(dbName here);
希望这会有所帮助 菲尔
答案 1 :(得分:1)
是的,但您可能不需要它。
我目前正在使用一个进程,我将附加数据库附加到wbx911 / Tim Post的答案中。但是如果要附加原始数据库的副本(例如,由项目/解决方案构建创建的副本),则不需要对它们进行删除。如果没有连接到db,它将在下一次测试运行时被覆盖。
如果您附加了大量数据库副本,或者只是想清理附加的所有内容,那么您可以使用如下所示的存储过程,附加到localDb实例的主数据库(我个人使用的例子:
CREATE PROCEDURE [dbo].[DettachTestDatabases]
AS
BEGIN
DECLARE @imax INT,
@i INT
DECLARE @Name VARCHAR(255)
DECLARE @DbsToDrop TABLE(RowID INT IDENTITY ( 1 , 1 ),
name VARCHAR(255)
)
INSERT @DbsToDrop
SELECT [name]
FROM [master].[sys].[databases]
WHERE
--Remove all local dbs with *SomeText*.mdf or SomeOtherTextin name
(name like '%SomeText%.mdf' or name like '%SomeOtherText%')
-- Exclude VS test dbs (add more as required...)
and (name not like '%TESTS.%');
SET @imax = @@ROWCOUNT
SET @i = 1
WHILE (@i <= @imax)
BEGIN
SELECT @Name = name
FROM @DbsToDrop
WHERE RowID = @i
EXEC master.dbo.sp_detach_db @dbname = @Name;
PRINT 'Dettatched ' + @Name;
SET @i = @i + 1;
END --while
END --sp
GO
我正在使用命名约定来确定要删除的dbs(因此是类似的语句)。 Visual Studio附加了几个db(或者至少我认为它们属于VS)来管理测试结果,我不想分离,(因此“不喜欢”条件)。 ther是一个master.dbo.sp_detach_db,它按名称分离,所以你真的只需要引用名称,但由于localdb名称可能有点疯狂,查找将很有用。
我在测试结束时还没有自动化,因为我觉得不需要(因为覆盖工作正常),但我可以随时随地在SSMS中执行它。但是如果您觉得有必要,您只需要从清理代码中管理对SP的调用。
附加dbs在某种程度上是一个昂贵的过程。我选择了一个清理方法/ SP来删除任何变量数据并重新安装表以使db处于一致状态,这非常快,而不是重新附加数据库。
如果你发现任何改进点,我真的很想知道它们!
答案 2 :(得分:1)
您使用的单元测试框架是否允许您附加清理方法(即AssemblyAttribute在MS测试中,OneTimeTearDown在NUnit 3中,shared context在XUnit中?如果是这样,您可以连接类似下面的内容,以便在测试结束时自动分离数据库。
public static void CleanUp()
{
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
var sql = "DECLARE @dbName NVARCHAR(260) = QUOTENAME(DB_NAME());\n" +
"EXEC('exec sp_detach_db ' + @dbName + ';');";
command.CommandText = sql;
command.ExecuteNonQuery();
}
}
}
答案 3 :(得分:0)
如果您正在讨论单元测试,例如xUnit,那么您可以添加到测试本身的属性,以便对任何触及数据库的内容进行回滚。
实际上,它在企业级事务处理中运行测试。这使得每个测试的数据都保持稳定,您不需要模拟数据库;它可以成为一种有效的验收测试。
例如(在xUnit中):
[Fact]
[AutoRollback]
public void Should_Insert_Valid_Data()
{
// Arrange: presume there's an object, sut, that supports insert,
// and you have some data
// Act:
int key = sut.Insert(data);
// Assert:
Assert.True(key > 0, "Expected a primary key to be returned");
var inserted = sut.Get(key);
Assert.Equal<DataClassName>(data, inserted, CompareAllButKey);
}
(fyi:“sut”是“被测试的情况”或“被测试的对象”)
在“Strategies for Isolating the Database in Tests”上看到这篇文章可能会有所帮助。该文章的最后还有一些其他不错的链接。
BTW,我使用xUnit作为示例,但其他测试框架具有类似的属性来控制回滚。答案 4 :(得分:-3)
像这样:
// ProjectPath/bin/Debug/dbfile.mdf
[TestInitialize]
public void SetUp()
{
AppDomain.CurrentDomain.SetData(
"DataDirectory", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ""));
}