2016-01-05 68 views
1

我們得到了一些使用SQL Server數據庫的單元測試。爲了使至少每個測試夾具獨特並且獨立於其他測試夾具,我嘗試在每個測試夾具開始之前恢復數據庫。每個測試都會打開並關閉其例程中的連接和數據庫。在單元測試之間恢復數據庫:數據庫仍在使用中

要在第一個測試夾具工作得很好之前恢復數據庫,但在第二個測試夾具之前(連接和數據庫已打開並關閉後)恢復數據庫則不會。

我把這個問題包括進去了。下面是這兩個樣品測試(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); 
     } 
    } 

的基礎測試類將在每次測試夾具前做恢復作業:

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)。爲什麼數據庫仍在使用中,我怎樣才能正確地關閉它?

+1

其實你應該以這樣的方式重構你的代碼(抽象),你不需要數據庫來測試你的代碼。現在,您不僅僅在測試「被測單元」,而是在測試數據庫內容。 –

+0

這是相關的:[錯誤 - 由於數據庫正在使用而無法獲得獨佔訪問](http://stackoverflow.com/questions/22209499/error-exclusive-access-could-not-be-obtained-because- the-database-is-in-use/22209822#22209822) – DMason

+0

@MikkoViitala感謝您的建議。在我們的單元測試中,我們通過BLL和DAL明確測試插入,更新和刪除操作。所以測試函數的關鍵功能是與數據庫一起工作。正如你所建議的那樣,我很困惑如何以抽象的重構方式測試那些以SQL語句結尾的邏輯(也需要進行測試)。 – modiX

回答

1

你需要殺死恢復之前連接到數據庫的所有進程:

sqlServer.KillAllProcesses(destinationDatabase) 

檢查documentation瞭解更多詳情。

+0

好的,這個工程。但爲什麼這是必需的。我的意思是,一旦'SqlConnection'對象調用'Dispose()'不應該自動執行此操作?我想這是某種緩存來重新打開它,不是嗎? – modiX

+0

您首次調用'restoreDatabase'數據庫可能會使連接處於打開狀態。 – Jaco

+0

剛剛測試過,不,不是。 – modiX