在单元测试之间恢复数据库:数据库仍在使用中
Recover database between unit tests: Database is still in use
我们得到了一些与 SQL 服务器数据库一起工作的单元测试。为了至少使每个测试装置唯一且独立于其他测试装置,我尝试在每个测试装置开始之前恢复数据库。每个测试都在其例程中打开和关闭连接和数据库。
在第一个测试夹具之前恢复数据库效果很好,但在第二个测试夹具之前(在打开和关闭连接和数据库之后)恢复数据库就不行了。
我封装并隔离了问题。这是两个示例测试(NewUnitTest1 将首先执行):
using NUnit.Framework;
using System.Data;
using System.Data.SqlClient;
[TestFixture]
class UnitTest1 : BaseTest
{
[Test]
public void NewUnitTest1()
{
string conString = ConnectionStringHelper.GetConnectionString(SCADADatabases.ConfigurationDatabase); // Helper method to optain connection string, is correct
using (SqlConnection dbConn = new SqlConnection(conString))
{
SqlCommand cmd = dbConn.CreateCommand();
cmd.CommandText = "SELECT * FROM TB_PV";
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
} // Dispose should close connection and database ...
Assert.IsTrue(true);
}
}
[TestFixture]
class UnitTest2 : BaseTest
{
[Test]
public void NewUnitTest2()
{
Assert.IsTrue(true);
}
}
基础测试 class 将在每个测试夹具之前执行恢复工作:
using My.Core.Helper;
using My.Core.UnitTest.Properties;
using My.DBRestore.Core;
using My.Domain;
using Microsoft.SqlServer.Management.Smo;
using NUnit.Framework;
using System;
using System.Data;
using System.IO;
/// <summary>
/// Base test class any test class can inherit from.
/// </summary>
public abstract partial class BaseTest
{
/// <summary>
/// Executes before all tests of this class start.
/// </summary>
[TestFixtureSetUp]
public virtual void FixtureSetUp()
{
Console.WriteLine("Recover database ... ");
restoreDatabase("MYDATABASE", @"D:\MYBACKUP.BAK", "");
Console.WriteLine("Run tests in " + this.GetType() + " ...");
}
private void restoreDatabase(string destinationDatabase, string backupFile, string dbPath)
{
Microsoft.SqlServer.Management.Smo.Server sqlServer = new Microsoft.SqlServer.Management.Smo.Server(Properties.Settings.Default.SQLInstance);
Microsoft.SqlServer.Management.Smo.Restore restore = new Microsoft.SqlServer.Management.Smo.Restore();
restore.Action = Microsoft.SqlServer.Management.Smo.RestoreActionType.Database;
restore.Devices.Add(new Microsoft.SqlServer.Management.Smo.BackupDeviceItem(backupFile, Microsoft.SqlServer.Management.Smo.DeviceType.File));
System.Data.DataTable dt = restore.ReadBackupHeader(sqlServer);
restore.FileNumber = Convert.ToInt32(dt.Rows[dt.Rows.Count - 1]["Position"]);
dt = restore.ReadFileList(sqlServer);
int indexMdf = dt.Rows.Count - 2;
int indexLdf = dt.Rows.Count - 1;
Microsoft.SqlServer.Management.Smo.RelocateFile dataFile = new Microsoft.SqlServer.Management.Smo.RelocateFile();
string mdf = dt.Rows[indexMdf][1].ToString();
dataFile.LogicalFileName = dt.Rows[indexMdf][0].ToString();
dataFile.PhysicalFileName = Path.Combine(dbPath, destinationDatabase + Path.GetExtension(mdf));
Microsoft.SqlServer.Management.Smo.RelocateFile logFile = new Microsoft.SqlServer.Management.Smo.RelocateFile();
string ldf = dt.Rows[indexLdf][1].ToString();
logFile.LogicalFileName = dt.Rows[indexLdf][0].ToString();
logFile.PhysicalFileName = Path.Combine(dbPath, destinationDatabase + Path.GetExtension(ldf));
restore.RelocateFiles.Add(dataFile);
restore.RelocateFiles.Add(logFile);
restore.Database = destinationDatabase;
restore.ReplaceDatabase = true;
restore.SqlRestore(sqlServer); // <- this is where the FailedOperationException is thrown on the second execution
}
}
如前所述,第一次恢复效果很好。第二次 FailedOperationException 声明:无法独占访问数据库,因为数据库当前正在使用中。 RESTORE DATABASE 将因错误而停止。 (本人人工翻译)
我们使用的是最新的 NUnit 2 版本 (2.6.4)。为什么数据库仍在使用中以及如何正确关闭它?
您需要在恢复之前终止连接到数据库的所有进程:
sqlServer.KillAllProcesses(destinationDatabase)
查看 documentation 了解更多详情。
我们得到了一些与 SQL 服务器数据库一起工作的单元测试。为了至少使每个测试装置唯一且独立于其他测试装置,我尝试在每个测试装置开始之前恢复数据库。每个测试都在其例程中打开和关闭连接和数据库。
在第一个测试夹具之前恢复数据库效果很好,但在第二个测试夹具之前(在打开和关闭连接和数据库之后)恢复数据库就不行了。
我封装并隔离了问题。这是两个示例测试(NewUnitTest1 将首先执行):
using NUnit.Framework;
using System.Data;
using System.Data.SqlClient;
[TestFixture]
class UnitTest1 : BaseTest
{
[Test]
public void NewUnitTest1()
{
string conString = ConnectionStringHelper.GetConnectionString(SCADADatabases.ConfigurationDatabase); // Helper method to optain connection string, is correct
using (SqlConnection dbConn = new SqlConnection(conString))
{
SqlCommand cmd = dbConn.CreateCommand();
cmd.CommandText = "SELECT * FROM TB_PV";
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
} // Dispose should close connection and database ...
Assert.IsTrue(true);
}
}
[TestFixture]
class UnitTest2 : BaseTest
{
[Test]
public void NewUnitTest2()
{
Assert.IsTrue(true);
}
}
基础测试 class 将在每个测试夹具之前执行恢复工作:
using My.Core.Helper;
using My.Core.UnitTest.Properties;
using My.DBRestore.Core;
using My.Domain;
using Microsoft.SqlServer.Management.Smo;
using NUnit.Framework;
using System;
using System.Data;
using System.IO;
/// <summary>
/// Base test class any test class can inherit from.
/// </summary>
public abstract partial class BaseTest
{
/// <summary>
/// Executes before all tests of this class start.
/// </summary>
[TestFixtureSetUp]
public virtual void FixtureSetUp()
{
Console.WriteLine("Recover database ... ");
restoreDatabase("MYDATABASE", @"D:\MYBACKUP.BAK", "");
Console.WriteLine("Run tests in " + this.GetType() + " ...");
}
private void restoreDatabase(string destinationDatabase, string backupFile, string dbPath)
{
Microsoft.SqlServer.Management.Smo.Server sqlServer = new Microsoft.SqlServer.Management.Smo.Server(Properties.Settings.Default.SQLInstance);
Microsoft.SqlServer.Management.Smo.Restore restore = new Microsoft.SqlServer.Management.Smo.Restore();
restore.Action = Microsoft.SqlServer.Management.Smo.RestoreActionType.Database;
restore.Devices.Add(new Microsoft.SqlServer.Management.Smo.BackupDeviceItem(backupFile, Microsoft.SqlServer.Management.Smo.DeviceType.File));
System.Data.DataTable dt = restore.ReadBackupHeader(sqlServer);
restore.FileNumber = Convert.ToInt32(dt.Rows[dt.Rows.Count - 1]["Position"]);
dt = restore.ReadFileList(sqlServer);
int indexMdf = dt.Rows.Count - 2;
int indexLdf = dt.Rows.Count - 1;
Microsoft.SqlServer.Management.Smo.RelocateFile dataFile = new Microsoft.SqlServer.Management.Smo.RelocateFile();
string mdf = dt.Rows[indexMdf][1].ToString();
dataFile.LogicalFileName = dt.Rows[indexMdf][0].ToString();
dataFile.PhysicalFileName = Path.Combine(dbPath, destinationDatabase + Path.GetExtension(mdf));
Microsoft.SqlServer.Management.Smo.RelocateFile logFile = new Microsoft.SqlServer.Management.Smo.RelocateFile();
string ldf = dt.Rows[indexLdf][1].ToString();
logFile.LogicalFileName = dt.Rows[indexLdf][0].ToString();
logFile.PhysicalFileName = Path.Combine(dbPath, destinationDatabase + Path.GetExtension(ldf));
restore.RelocateFiles.Add(dataFile);
restore.RelocateFiles.Add(logFile);
restore.Database = destinationDatabase;
restore.ReplaceDatabase = true;
restore.SqlRestore(sqlServer); // <- this is where the FailedOperationException is thrown on the second execution
}
}
如前所述,第一次恢复效果很好。第二次 FailedOperationException 声明:无法独占访问数据库,因为数据库当前正在使用中。 RESTORE DATABASE 将因错误而停止。 (本人人工翻译)
我们使用的是最新的 NUnit 2 版本 (2.6.4)。为什么数据库仍在使用中以及如何正确关闭它?
您需要在恢复之前终止连接到数据库的所有进程:
sqlServer.KillAllProcesses(destinationDatabase)
查看 documentation 了解更多详情。