SQL Server

SSIS 套件的單元和整合測試

Pavle Guduric

下載代碼示例

我工作我們在這裡建了提取物,專案轉換和載入 (ETL) 過程與 150 多個套裝軟體。 其中許多包含複雜的轉換和業務邏輯,因而是不簡單"將資料從 A 點到 B 點"的套裝軟體。 進行大的改動不直截了當,結果往往是不可預測。 要測試的包,我們用來測試資料填充輸入的表或檔,執行包或任務在 Microsoft 商業智慧發展工作室 (投標),編寫一個 SQL 查詢和比較,我們所認為的包所生成的輸出是正確的輸出。 更經常我們剛剛跑上一個示例資料庫的整個 ETL 過程,只是抽樣的輸出資料末尾的過程 — — 非常耗時且不可靠的過程。 不幸的是,這是SQL Server整合服務 (SSIS) 開發人員之間的共同做法。 更具挑戰性的就是要確定後續的包一包的執行有何影響。 當你構建你的 ETL 過程,創建網路連接的包和不同資源。 它很難維持所有這些在一切時代之間的眾多依賴項的完整概述。

這篇文章解釋了如何執行單元和集成測試的 SSIS 包通過引入一個名為 SSISTester,它建立在 SSIS 託管 API 庫。 閱讀完本文後你應該能夠使用所介紹的技術和工具來自動化單元和集成測試您現有的和新的 SSIS 專案。 要對文章的理解,您應該與 SSIS 和 C# 的以往經驗。

SSISTester

當我開始思考一個 SSIS 包的測試框架時,三個方面,重要的是找到 首先,我想要寫測試使用的Visual Studio的測試框架,所以涉及安裝、 驗證和清理 (aka 拆機) 的典型方法步驟不得不將應用到類似 UX。 第二,我想要使用現有的和行之有效的工具來編寫、 執行和管理測試。 再次,Visual Studio是顯而易見的選擇。 第三,要對能夠在 C# 中編寫測試代碼。 這一點我寫了 SSISTester,.NET 庫之上,SSIS 運行庫並公開的 API,允許您編寫和執行 SSIS 包的測試。 中描述的主要邏輯元件庫的圖1

Logical Components of the SSISTester Library
圖 1 邏輯元件的 SSISTester 圖書館

包庫用於存儲目標包原始 XML 表示形式。 每次執行測試時,Microsoft.SqlServer.Dts.Runtime.Package 類的新實例進行反序列化從 XML 的所有欄位和屬性設置為其預設值。 這是重要的因為你不想不同的測試目標到不慎任何的重用值由先前的測試設定相同的包。

測試存儲庫中存儲的測試類的實例。 這些類包含執行測試案例的方法。 在測試執行時,由測試引擎調用這些方法。 創建測試類時必須遵循的具體規則將稍後詳細介紹。

中繼資料包含裝飾的測試類,所以它可以被認可作為測試執行所需的屬性。 入測試存儲庫載入測試時,測試引擎看起來這些屬性。

測試上下文表示的類集,提供對不同階段的測試執行的運行時資訊的訪問。 例如,您可以使用這些類來訪問不同方面的測試,如變數、 屬性、 前面的約束、 連線管理員當前正在執行的任務,包錯誤等等包。

測試引擎指的核心類和直接利用託管的 SSIS 運行庫 SSISTester API 的介面。 它們用於載入包和入其各自的資料庫,以及執行測試,測試結果創建測試類。

迷你 ETL

要創建包和測試類,我會用Visual Studio2012年和SQL Server2012 年,和我用三個包來說明一個簡單的 ETL 方案中哪些客戶交付作為一個文字檔的資料是轉換和存儲在一個資料庫內。 CopyCustomers.dtsx、 LoadCustomers.dtsx 和 Main.dtsx 的包。 CopyCustomers.dtsx 將 Customers.txt 檔從一個位置複製到另一個,路上它將轉換為大寫文本的所有客戶名稱。 Customers.txt 是一個簡單的 CSV 檔包含的客戶 id 和名稱就像這樣:

id,name
1,company1
5,company2
11,company3

LoadCustomers.dtsx 載入演示資料庫的轉換的名稱。 它將資料載入到目標表,稱為客戶之前­暫存,它將截斷以前存儲的所有資料。 在這一進程的結束,它存儲到變數中的客戶數目。 在這裡是要創建演示資料庫和 CustomersStaging 表的腳本:

CREATE
DATABASE [Demo]
GO
USE [Demo]
GO
CREATE TABLE [dbo].[CustomersStaging](
  [Id] [int] NULL,
  [Name] [nvarchar](255) NULL
) ON [PRIMARY]
GO

Main.dtsx 包中包含兩個執行包任務,執行 sub-packages CopyCustomers.dtsx 和負載­Customers.dtsx,分別。 在 CopyCustomers.dtsx 和 LoadCustomers.dtsx 的連線管理員配置使用運算式和包變數。 從父包配置從另一個包內執行時檢索相同的包變數。

建立單元測試

首先,創建一個主控台專案和添加到 SSIS 的程式集引用。Test.dll,SSIS。Test.Report.dll。 我要首先創建單元測試包的 CopyCustomers.dtsx。 圖 2 顯示的控制流 (左) 和 CopyCustomers.dtsx (右) 的資料流程。

Control Flow (Left) and Data Flow (Right) of the CopyCustomers.dtsx Package
圖 (左) 2 控制流和資料流程 (右) 的 CopyCustomers.dtsx 包

每個單元測試是從 BaseUnitTest 類派生和必須與單元測試屬性修飾的單個類中實現的:

[UnitTest("CUSTOMERS", "CopyCustomers.dtsx")]
public class CopyCustomersTest : BaseUnitTest{
  protected override void Setup(SetupContext context){}
  protected override void Verify(VerificationContext context){}
  protected override void Teardown(TeardownContext context){}
}

單元測試屬性標記作為一個單元測試類執行測試引擎所能找到它。 第一個參數對應于包存儲庫中的目標包將會載入測試執行期間,在本示例中的客戶。 第二個參數可以是目標包、 任務的控制流,事件處理常式的路徑或路徑前面的約束中的路徑名稱。 在此示例中它是 CopyCustomers.dtsx 包的名稱,因為我想要測試整個包。 基本上,單元測試屬性告訴測試引擎看客戶資料庫中包的 CopyCustomers.dtsx 和 CopyCustomersTest 測試期間執行它。

BaseUnitTest 所有單元測試實現需要從派生類的基類包含必須落實的三種方法:安裝程式、 驗證和拆卸。

這三個方法都執行不同的測試階段。 Setup 方法運行之前,測試引擎執行目標包。 安裝程式準備包和所有的輸入和輸出的套裝軟體依賴所以它可以成功地驗證和執行。 在以下示例中,我設置的路徑到包變數用作連線管理員中的連接字串:

protected override void Setup(SetupContext context){
  if(File.Exists(@"C:\TestFiles\Archive\Customers.txt"))
    File.Delete(@"C:\TestFiles\Archive\Customers.txt");
  if(File.Exists(@"C:\TestFiles\Converted\Customers.txt"))
    File.Delete(@"C:\TestFiles\Converted\Customers.txt");
  DtsVariable sourceFile = context.Package.GetVariable("SourcePath");
  sourceFile.SetValue(@"\\nc1\Customers\Customers.txt");
  DtsVariable destinationFile = 
    context.Package.GetVariable("DestinationPath");
  destinationFile.SetValue(@"C:\TestFiles\Archive\Customers.txt");
  DtsVariable convertedFile = 
    context.Package.GetVariable("ConvertDestinationPath");
  convertedFile.SetValue(@"C:\TestFiles\Converted\Customers.txt");
}

Setup 方法已成功執行後,測試引擎執行目標包。 包已執行時,測試引擎調用驗證的方法,我可以檢查我的說法是否真實:

protected override void Verify(VerificationContext context){
  Assert.AreEqual(true, 
    context.Package.IsExecutionSuccess);
  Assert.AreEqual(true, 
    File.Exists(@"C:\TestFiles\Archive\Customers.txt"));
  Assert.AreEqual(true, 
    File.Exists(@"C:\TestFiles\Converted\Customers.txt"));
  string[] lines = 
    File.ReadAllLines(@"C:\TestFiles\Converted\Customers.txt");
  Assert.AreEqual("COMPANY2", lines[2].Split(',')[1]);
}

第一個 assert 檢查包是否已成功執行。 第二個確定是否 FST 複製原始程式碼檔的檔案系統任務複製到 C:\TestFiles\Archive\ 資料夾中的 \\nc1\Customers\Customers.txt 檔。 最後兩個斷言驗證是否 DFT 轉換客戶名稱資料流程任務正確地轉換為大寫的公司名稱。 早些時候,簡要介紹測試上下文了。 在這裡你可以看到我如何使用上下文參數來訪問包內的安裝和驗證方法的物件。

在測試結束時,我使用的拆卸方法要刪除的檔被覆制或創建的套裝軟體:

protected override void Teardown(TeardownContext context){
  File.Delete(@"C:\TestFiles\Archive\Customers.txt");
  File.Delete(@"C:\TestFiles\Converted\Customers.txt");
}

測試控制流任務

測試可以目標以及控制流中的特定任務。 例如,要在 LoadCustomers.dtsx 包中測試 DFT 負載客戶資料流量,我用於附加參數的單元測試的特性,稱為 ExecutableName,告訴我想要測試這項任務的測試引擎:

[UnitTest("CUSTOMERS", "LoadCustomers.dtsx",ExecutableName =
  @"\[LoadCustomers]\[SEQC Load]\[DFT Load customers]"))]
public class LoadCustomersTest : BaseUnitTest{
}

ExecutableName 表示路徑,結合名稱開始的所有嵌套容器的包名稱。

LoadCustomers.dtsx 的控制和資料流程所示圖3

Control Flow (Left) and Data Flow (Right) of the LoadCustomers.dtsx Package
圖 (左) 3 控制流和資料流程 (右) 的 LoadCustomers.dtsx 包

當測試針對特定的任務時,這項任務只是引擎執行的測試。 如果目標任務的成功執行取決於前面的任務的執行,執行這些任務的結果需要手動生成。 DFT 負載客戶資料流量預計的目標表,由 SQL 截斷 CustomersStaging 任務會被截斷。 進一步,資料流量預計將轉換後的 Customers.txt 檔的特定位置。 由 CopyCustomers.dtsx 套裝程式創建此檔,因為我需要手動複製它。 這裡是這所有的安裝方法:

protected override void Setup(SetupContext context){
  string dbConStr = @"Data Source=.;Integrated Security=SSPI;Initial Catalog=Demo";
  string ssisConStr = @"Provider=SQLNCLI11;" + dbConStr;
  File.Copy(@"\\nc1\Customers\Customers.txt", 
    @"C:\TestFiles\Converted\Customers.txt");
  context.DataAccess.OpenConnection(dbConStr);
  context.DataAccess.ExecuteNonQuery("truncate table [dbo].[CustomersStaging]");
  context.DataAccess.CloseConnection();
  DtsConnection conn = context.Package.GetConnection("CustomerDB");
  conn.SetConnectionString(ssisConnStr);
  conn = context.Package.GetConnection("CustomersSrc");
  conn.SetConnectionString(@"C:\TestFiles\Converted\Customers.txt");
}

通過使用 File.Copy,我將 Customers.txt 複製到資料流程所期望的位置。 然後我使用 SetupCoNtext 的資料訪問屬性在目標表上執行 truncate 語句。 此屬性公開一個羽量級ADO.NET包裝,使您能夠執行 SQL 命令,而無需使用 SqlConnection 和 SqlCommand 類,每次你想要訪問的資料庫。 結束時,我使用的包屬性設置為基礎的連線管理員的連接字串。

測試前面的約束

寫作測試的目標前面的約束也是可能的。 例如,前面的 SCR CheckCount 腳本任務 LoadCustomers.dtsx 包中的 CountConstraint 有一個運算式來檢查該變數 CustomerCount 是否大於零。 如果此運算式計算結果為 true,SEQC 裝載任務執行成功,則執行該腳本任務。 圖 4 顯示完整的單元測試。

圖 4 完成單元測試

[UnitTest("CUSTOMERS", "LoadCustomers.dtsx",
    PrecedenceConstraintsTestOnly = true))]
public class LoadCustomersConstraintsTest : BaseUnitTest{
  private DtsPrecedenceConstraint _countConstraint;
  protected override void Setup(SetupContext context){
    DtsVariable variable = context.Package.GetVariable("CustomerCount");
    variable.SetValue(0);
    _countConstraint =
      context.Package.GetPrecedingConstraintForPath(
      @"\[LoadCustomers]\[SCR    CheckCount].[CountConstraint]");
    _countConstraint.SetExecutionResult(DtsExecutionResult.Success);
  }
  protected override void Verify(VerificationContext context)
  {
    Assert.AreEqual(false, _countConstraint.Evaluate());
  }
  protected override void Teardown(TeardownContext context){}
}

要準備優先約束進行測試,需要做兩件事。 首先,我要 CustomerCount 變數設置為某個值,因為它引用了中優先約束的運算式。 在這種情況下,我選擇了 0。 接下來,我設置了前面的任務的執行結果,為成功、 失敗或完成。 我這樣做是通過使用 SetExecutionResult 方法來類比的前面的任務的成功。 這意味著 CountConstraint 應求值為 false,這是我期望中的驗證方法。 只有一個類可以在你執行前面的所有約束的單元測試包中。 因此,沒有在單元測試屬性中,只有一個 Bool 標誌,通知引擎這是單元測試類的優先約束的特定約束的目標路徑。 此的原因是與優先約束,不是需要包或任務執行之前調用的驗證方法。

執行單元測試

我可以在我的測試執行之前,我需要將目標包和測試載入到其資料庫。 要做到這一點,我需要對測試引擎的引用。 打開 program.cs,然後從檔並替換這一個空的 Main 方法:

static void Main{
  IUnitTestEngine engine = 
    EngineFactory.GetClassInstance<IUnitTestEngine>();
  engine.LoadPackages("CUSTOMERS", @"C:\TargetPackages\");
  engine.LoadUnitTests();
  engine.ExecuteUnitTestsWithGui();
}

第一行創建一個測試引擎對引用。 從 C:\TargetPackages\ 到客戶資料庫資料夾中載入的所有套裝軟體,使用 LoadPackages 方法。 LoadUnitTests 方法將載入到指定的測試存儲庫點綴的單元測試屬性的所有類中調用程式集。 最後,我呼籲啟動測試的執行,並打開監控的 GUI 中所示的 ExecuteUnitTestsWithGui 圖5

The Monitoring GUI During the Execution of Tests
圖 5 監測 GUI 測試的執行過程

在 GUI 圖5是實用的如果您想要在您的電腦上本地測試,你不想要啟動Visual Studio。 如果您想要測試伺服器上的包,你可以做小修改程式並安排它例如直接生成伺服器上,運行測試:

static void Main{
  IUnitTestEngine engine = 
    EngineFactory.GetClassInstance<IUnitTestEngine>();
  engine.LoadPackages("CUSTOMERS", @"C:\TargetPackages\");
  engine.LoadUnitTests();
  engine.ExecuteUnitTests();
  engine.UnitTestResults.SaveAsHtml(@"C:\TestResults\");
}

IUnitTestEngine 介面具有 UnitTestResults 屬性,以允許您訪問測試結果,並將它們保存為 HTML 報告。 我用 ExecuteUnitTestsWithGui 替換 ExecuteUnitTests,而不顯示監控 GUI。 您還可以運行測試Visual Studio裡面或使用 ReSharper,所以你不需要啟動的主控台程式。 若要執行此操作,創建新的類稱為 SSISUnitTestAdapter,所示圖 6

圖 6 SSISUnitTestAdapter 類

[TestClass]
public class SSISUnitTestAdapter{
  IUnitTestEngine Engine {get;set;}
  [AssemblyInitialize]
  public static void Prepare(TestContext context){
    Engine = EngineFactory.GetClassInstance<IUnitTestEngine>();
    Engine.LoadPackages("CUSTOMERS", @"C:\TargetPackages\");
    Assembly testAssembly =
      Assembly.GetAssembly(typeof(CopyCustomersTest));
    Engine.LoadRepositoryUnitTests(testAssembly, "CUSTOMERS");
  }
  [TestMethod]
  public void CopyCustomersTest(){
    Engine.ExecuteUnitTest(typeof(CopyCustomersTest));
  }
  [TestMethod]
  public void LoadCustomersTest(){
    Engine.ExecuteUnitTest(typeof(LoadCustomersTest));
  }
  [TestMethod]
  public void LoadCustomersConstraintsTest(){
    Engine.ExecuteUnitTest(typeof(LoadCustomersConstraintsTest));
  }
}

如果你共事過微軟的單元測試框架之前,你會認出的 TestClass、 AssemblyInitialize 和 TestMethods 的屬性。 三種測試方法,CopyCustomersTest、 LoadCustomersTest、 LoadCustomersConstraintsTest、 換行的 ExecuteUnitTest 方法,後者反過來執行安裝、 驗證和拆機的類作為參數傳遞的方法調用。 準備方法創建的測試引擎物件和載入包和單元測試到他們各自的資料庫。 我用稍微不同的方法,稱為 LoadRepositoryUnitTests 負載測試綁定到客戶資料庫只。 這是非常有用的如果你不想要載入的所有測試。 您可以通過點擊測試執行所有測試 |執行 |Visual Studio中的所有測試。

創建集成測試

單元測試的基本理念是隔離的所有可能影響其他套裝軟體或任務可能會對一個正在進行測試。 有時它可能很難創建實際的測試安裝程式和所需的單元測試,以確保包或任務正在進行測試的初步條件的行為像一個完整的 ETL 過程的一部分。 因為你通常執行 ETL 過程與一些套裝軟體,您需要執行集成測試確定,每個套裝軟體的工作以及運行時作為這一進程的一部分。 這個想法是定義探測點在 ETL 過程中要執行測試,而不必停止整個進程的位置。 進程前進,到達探測點,執行您的測試的您可以驗證"活"的工作進展 ETL 過程 ; 因此名稱、"現場測試"。

現場測試基本上是後置條件 — — 定義為一個包、 任務或事件處理常式 — — 的需要得到滿足後包中,已執行任務或事件處理常式。 此 post-condition 對應于單元測試的驗證步驟。 因為它是不可能編寫,測試執行包之前或之後執行清理步驟,現場測試是不同的單元測試。 這是因為不同的單元測試、 現場測試並不執行包 ; 它是圓的其他方式:當它來到 post-condition 定義的探測點,執行測試包。

圖 7 說明了這種差異。 請注意這兩個數字中套裝軟體的位置。 當正在運行單元測試時,測試引擎通過調用其安裝、 驗證和拆卸方法顯式執行單元測試。 作為此安裝程式驗證拆卸序列的一部分執行的包。

Sequence Diagrams for Unit Test (Left) and Live Test (Right) Execution
圖 7 序列圖為單元測試 (左) 和生活測試 (右) 執行

另一方面,當運行的現場測試,測試引擎執行包顯式地,進而觸發執行套裝軟體和其任務後的操作方法的執行。

創建包的 CopyCustomers.dtsx 現場測試,以創建新的類稱為 CopyCustomers,所示圖 8

圖 8 CopyCustomers 類

[ActionClass("CUSTOMERS", "CopyCustomers.dtsx")]
public class CopyCustomers : BaseLiveTest{ 
  [ActionMethod(@"\[CopyCustomers]")]
  public void TestWholePackage(ActionContext context){
    Assert.AreEqual(true, context.Package.IsExecutionSuccess);
  }
  [ActionMethod(@"\[CopyCustomers]\[FST Copy Source File]")]
  public void TestCopySourceFile(ActionContext context){
    Assert.AreEqual(true, 
        context.ActiveExecutable.IsExecutionSuccess);
    Assert.AreEqual(true, 
        File.Exists(@"C:\TestFiles\Archive\Customers.txt"));
  }
  [ActionMethod(@"\[CopyCustomers]\[DFT Convert customer names]")]
  public void TestConvertCustomersNames(ActionContext context){
    Assert.AreEqual(true, context.ActiveExecutable.IsExecutionSuccess);
    string[] lines = 
        File.ReadAllLines(@"C:\TestFiles\Converted\Customers.txt");
    Assert.AreEqual("COMPANY2", lines[2].Split(‘,’)[1]);
  }
}

每個現場測試類必須從 BaseLiveTest 類派生,與單元測試相比的主要區別。 BaseLiveTest 類用於內部測試引擎執行現場測試並沒有要重寫的方法。 ActionClass 屬性將此類標記作為現場測試。 參數相同,使用時,該單元測試屬性 — — 存儲庫和目標的一攬子計畫。 請注意與不同的地方在一個單一的、 單獨的類中實現每個測試的單元測試,只有一個類實現所需所有後的包。 現場測試類可以有任意數目的後,應進行評估。 這些所對應的單元測試中的驗證方法和作為裝飾的 ActionMethod 屬性的方法實現。 在示例中圖 8,我有一個 post-condition 包中的每個任務和一個包的本身。 ActionMethod 接受目標任務,這是 ExecutableName 的單元測試屬性相同的路徑。 這是告訴測試引擎執行此方法已在執行目標任務時。 不同的驗證方法,這始終執行,這些後可能不會調用的時候,例如,目標任務不成功地執行或上述約束條件計算結果為 false。 ActionCoNtext 參數提供相同的功能的 VerificationCoNtext。

執行現場測試

執行單元測試時執行現場測試的必要步驟略有不同。 若要執行現場測試,替換 program.cs,然後從檔中的 Main 方法中的代碼圖 9

圖 9 執行現場測試的主要方法

static void Main{
  string dbConStr = @"Data Source=.;Integrated Security=SSPI;Initial Catalog=Demo";
  string ssisConStr = @"Provider=SQLNCLI11;" + dbConStr;
  ILiveTestEngine engine = 
    EngineFactory.GetClassInstance<ILiveTestEngine>();
  engine.LoadPackages("CUSTOMERS", @"C:\TargetPackages\");
  engine.LoadActions();
  ExecutionParameters params = new ExecutionParameters();
  params.AddVariable(@"\[Main].[ConnectionString]", ssisConStr);
  params.AddVariable(@"\[Main].[CopyCustomersPath]", 
    @"C:\TargetPackages\CopyCustomers.dtsx");
  params.AddVariable(@"\[Main].[LoadCustomersPath]", 
    @"C:\TargetPackages\LoadCustomers.dtsx");
  params.AddVariable(@"\[Main].[ConvertDestinationPath]",
    @"C:\TestFiles\Converted\Customers.txt");
  params.AddVariable(@"\[Main].[DestinationPath]", 
    @"C:\TestFiles\Archive\Customers.txt");
  params.AddVariable(@"\[Main].[SourcePath]", 
    @"\\nc1\Customers\Customers.txt");
  engine.SetExecutionParameters(parameters);
  engine.ExecuteLiveTestsWithGui("CUSTOMERS", "Main.dtsx");
}

我需要 ILiveTestEngine,造成使用 EngineFactory 的一個實例。 載入包時相同,使用 IUnitTestEngine。 LoadActions 方法載入中調用程式集定義的所有操作,實際上是相當於負載­UnitTests。 然而,此時,相似性與單元測試將停止。 而不是執行單元測試,我告訴測試引擎執行的 Main.dtsx 包通過調用 ExecuteLiveTestsWithGui。

Main.dtsx 包啟動時,它會通過執行的 EPT CopyCustomers 任務運行 CopyCustomers.dtsx。 每個成功地完成了任務 CopyCustomers.dtsx 觸發器中的在 CopyCustomersLiveTests 類中的相應操作方法之一。 它是重要的是要注意此測試隱式測試 CopyCustomers.dtsx 套裝軟體的配置設置。

配置的變數從 Main.dtsx 包繼承它們的值。 請注意這些變數作為一般檔案連線管理員的 CopyCustomers.dtsx 包中的連接字串。 基本上,這意味著在 CopyCustomers.dtsx 包中的任務的成功執行取決於價值回歸這兩個包之間是否工作正常。 這是一個簡單的例子的如何測試交互和包之間的依賴關係,但是你可以想像更複雜的方案,獨立的單元測試會足以涵蓋該測試案例。

測試引擎塔內件

核心實現的類的 SSISTester 圖書館的主要職能是 TestEngine。 它是通過 IUnitTestEngine 和 ILiveTestEngine 介面公開的內部類。 這兩種方法,揭示了大部分的內在邏輯是 LoadUnitTests (所示圖 10) 和 ExecuteUnitTests。

圖 10 LoadUnitTests 方法

public void LoadUnitTests(){
  Assembly assembly = Assembly.GetCallingAssembly();
  IEnumerable<Type> types = assembly.GetTypes().Where(t => t.GetCustomAttributes(false).OfType<UnitTestAttribute>().Any() && 
    t.BaseType != null && t.BaseType.Name.Equals("BaseUnitTest"));
  foreach (Type t in types)
  {
    var attribute =
      t.GetCustomAttributes(false).OfType<UnitTestAttribute>().Single();
    DtsPackage package =
      _packages[attribute.Repository].GetForName(attribute.PackageName);
    string executable = attribute.ExecutableName;
    bool precedenceTestOnly = attribute.PrecedenceConstraintsTestOnly;
    var test = (BaseUnitTest)Activator.CreateInstance(t);
    test.TestClass = t;
    test.SetTestTargets(package, executable, precedenceTestOnly);
    test.Started += BaseUnitTestStarted;
    test.Finished += BaseUnitTestFinished;
    _unitTests.Add(test);
  }
}

LoadUnitTests 基本上迴圈所有類的單元測試屬性裝飾和每個創建的實例。 這些實例然後被轉換為 BaseUnitTest,並分配,以前從包庫中載入目標包。 結束時,所有實例都保存在 _unitTests 清單中。 ExecuteUnitTests 的方法迴圈 BaseUnitTest 的所有實例,並調用 ExecuteTests 每個:

public void ExecuteUnitTests(){
  foreach (BaseUnitTest t in _unitTests){
    t.ExecuteTest();
  }
}

執行測試案例的方法中執行的實際執行單元測試 (所示圖 11) 在 BaseUnitTest 類中。

圖 11 執行測試案例方法

public void ExecutTest(){
  Result = new UnitTestResult(Package, Executable) { TestOutcome =
    TestOutcome.InProgress, StartedAt = DateTime.Now };
  ExecuteSetup(CreateSetupContext());
  if (!Result.IsSetupSuccess)
    ExecuteTeardown(CreateTeardownContext());
  else{
    if(!PrecedenceOnly)
      Executable.Execute();
    ExecuteVerify(CreateVerifyContext());
    ExecuteTeardown(CreateTeardownContext());
    Result.FinishedAt = DateTime.Now;
  }
}

這種方法最重要的方面是它執行的安裝程式、 驗證和拆卸方法,以及目標包。

總結

專案的同時,伴隨,在這裡介紹的示例應允許您開始測試您的 SSIS 專案。 自動化測試您的 SSIS 包中可以保存很長時間。 更重要的是重要,自動化測試是更可靠的因為它不斷地做,你可以覆蓋更多的包。 一旦你寫的測試,你可以始終運行它們自動的生成過程中。 最終,這意味著更少的錯誤和更好的品質。

Pavle Gudurić 位於德國的是一名軟體工程師。他在電子商務和幾個技術認證、 碩士學位和業務智慧 (BI) 解決方案在金融業的發展。他在到達 pavgud@gmail.com

感謝以下技術專家對本文的審閱:基督徒 Landgrebe (LPA) 和安德魯 Oakley (Microsoft)
基督徒 Landgrebe 帶領資料庫團隊在 LPA,專注于提供給客戶的金融和銀行業的 BI 解決方案。
安德魯 Oakley 是高級專案經理模式 & 團隊的做法。 之前成為專案經理,安德魯Visual Studio和.NET 平臺花了兩年來,作為技術的福音傳教士。 他當前專案的重點是圍繞建設不羈的持久性系統使用關係和 NoSQL 資料存儲的資料訪問指導。