tSQLt提供了一些功能以進行資料庫的單元測試的管理,也實作了一些可以隔離資料庫物件相依性的功能。底下是這些功能的簡介及一些心得。
Test Class的建立與執行
tSQLt提供了幾個功能,以用來建立Test Case。建立Test Case的第一步,就是呼叫tSQLt.NewTestClass
以建立一個test class
。這個步驟做的事情其實很單純,就是依據傳入的TestClass名稱建立同名的Schema,並且在Schema的定義中加入extended property的註記,以讓tSQLt在執行時可以辨識該Schema。
之後以Stored Procedure的形式建立Test Case,並且使用命名原則來辨識哪些SP是用來進行單元測試。該命名原則就是Stored Procedure的名稱需以test
開頭。底下就是一個Test Case的範例。
CREATE PROCEDURE LabHello.[test rate]
AS
BEGIN
DECLARE @actual MONEY;
DECLARE @rate DECIMAL(10,4); SET @rate = 1.2;
DECLARE @amount MONEY; SET @amount = 2.00;
SELECT @actual = dbo.ConvertCurrency(@rate, @amount);
DECLARE @expected MONEY; SET @expected = 2.4; --(rate * amount)
EXEC tSQLt.AssertEquals @expected, @actual;
END;
GO
當tSQLt進行測試程序時,會找出這些以test
開頭的SP,並開啟Transaction。當該SP執行結束時,再將Transaction進行rolled-back,以清掉測試過程中的各種異動。而測試的結果,則會記錄在該database的tSQLt.TestResult
這個table中。
以下介紹幾個管理TestClass會用到的功能:
NewTestClass
建立Test Class(Schema)
語法:
tSQLt.NewTestClass [@ClassName = ] 'class name'
RenameClass
修改Test Class的名稱
語法:
tSQLt.RenameClass [@SchemaName = ] 'class name'
, [@NewSchemaName = ] 'new class name'
DropClass
刪掉Test Class以及屬於該Test Class的物件
語法:
tSQLt.DropClass [@ClassName = ] 'class name'
RunAll
這個指令會執行該database上,所有的test case
語法:
tSQLt.RunAll
Run
這個指令可以依據輸入的參數,執行特定的測試案例
- 如果是test class的名稱,則執行屬於該test class的所有測試案例
- 如果是test case名稱,則執行該test case
- 如果是空白,則執行上一個有參數的Run指令。當有需求要重複測試時,就不需要每次都輸入參數。
語法:
tSQLt.Run [ [@testName = ] 'test name' ]
Assertions
單元測試有所謂的3A原則,tSQLt也提供一系列的功能作為Assert之用。
AssertEmptyTable:
檢驗目標Table的資料行數是否為0 語法:
tSQLt.AssertEmptyTable [@TableName = ] 'name of table to be checked'
[, [@FailMsg = ] 'message' ]
AssertEquals
檢驗預期值與實際值是否相同 語法:
tSQLt.AssertEquals [@expected = ] expected value
, [@actual = ] actual value
[, [@message = ] 'message' ]
AssertNotEquals
檢驗預期值與實際值是否不同
語法:
tSQLt.AssertNotEquals [@expected = ] expected value
, [@actual = ] actual value
[, [@message = ] 'message' ]
AssertEqualsString
檢驗預期字串與實際字串是否相同 語法:
tSQLt.AssertEqualsString [@expected = ] expected value
, [@actual = ] actual value
[, [@message = ] 'message' ]
AssertLike
檢驗預期值與實際值是否相同,而預期值可以使用Like
的語法表達式。
tSQLt.AssertLike [@ExpectedPattern = ] expected pattern
, [@Actual = ] actual value
[, [@Message = ] 'message' ]
範例如下:
EXEC tSQLt.AssertLike 'hello', 'hello'; -- pass
EXEC tSQLt.AssertLike '%el%', 'hello'; - pass
EXEC tSQLt.AssertLike 'h_llo', 'hello'; - pass
EXEC tSQLt.AssertLike '%oo%', 'hello'; - fail
AssertEqualsTable
檢測兩個Table內的資料內容是否相同,如果不同,還會顯示其差異內容
語法:
tSQLt.AssertEqualsTable [@Expected = ] 'expected table name'
, [@Actual = ] 'actual table name'
[, [@FailMsg = ] 'message' ]
AssertEqualsTableSchema
檢測兩個Table的Schema是否相同
語法:
tSQLt.AssertEqualsTableSchema [@Expected = ] 'expected table name'
, [@Actual = ] 'actual table name'
[, [@FailMsg = ] 'message' ]
AssertObjectExists
檢測資料庫物件是否存在
語法:
tSQLt.AssertObjectExists [@objectName = ] 'object name'
[, [@message = ] 'message' ]
AssertObjectDoesNotExist
檢測資料庫物件是否不存在
語法:
tSQLt.AssertObjectDoesNotExist [@objectName = ] 'object name'
[, [@message = ] 'message' ]
Fail
直接觸發一個測試錯誤,並可指定錯誤訊息
語法:
tSQLt.Fail [ [@Message0 = ] message part ]
[, [@Message1 = ] message part ]
[, [@Message2 = ] message part ]
[, [@Message3 = ] message part ]
[, [@Message4 = ] message part ]
[, [@Message5 = ] message part ]
[, [@Message6 = ] message part ]
[, [@Message7 = ] message part ]
[, [@Message8 = ] message part ]
[, [@Message9 = ] message part ]
隔離相依性
在單元測試中,會使用stub、mock、fake物件,以達到將測試的目標物件中相依元件隔離開來的目的。在tSQLt的架構中也一樣,tSQLt提供一些功能讓Stored Procedure、Function的相依性減到最低。
FakeTable
這個功能可以依據指定的Table Name建立一個沒有constraints的空Table。並且在執行測試時,直接取代原先的Table。這樣有兩個好處,一來進行測試時不會受到既有的資料的影響,二來塞入模擬資料到Table時比較簡單,因為沒有constraints。
語法
tSQLt.FakeTable [@TableName = ] 'table name'
, [[@SchemaName = ] 'schema name']
, [[@Identity = ] 'preserve identity']
, [[@ComputedColumns = ] 'preserve computed columns']
, [[@Defaults = ] 'preserve default constraints']
FakeFunction
這個功能是在進行測試時,可以讓一個預先建立的簡單的Function,取代原本實作所有商業邏輯的複雜Function。這是因為如果在測試一個Stored Procedure時,如果會叫用該複雜的Function,有可能該複雜Function邏輯出問題而影響到測試結果。在隔離相依性的需求下,就可以預先建立一個簡單的Function(可能是回傳一個固定值),替換掉原先複雜的Function。
語法:
tSQLt.FakeFunction [@FunctionName = ] 'function name'
, [@FakeFunctionName = ] 'fake function name'
SpyProcedure
這個功能與FakeFunction類似,不過是作用在Stored Procedure上。在測試案例中,使用此功能以指定的sql statement替換掉指定的Stored Procedure。同時,它還可以紀錄傳入到Stored Procedure的參數值,到額外建立的Table中,以進行trace及debug之用。
語法:
tSQLt.SpyProcedure [@ProcedureName = ] 'procedure name'
[, [@CommandToExecute = ] 'command' ]
RemoveObject
在測試案例中,這個功能可以暫時移除指定的資料庫物件(其實是透過更名的方式),然後再以自訂的mock物件取代原物件,已達到隔離隔離相依性的需求。
語法:
tSQLt.RemoveObject [@ObjectName= ] 'object name'
[, [@NewName = ] 'new object name' OUTPUT]
[, [@IfExists = ] ( 0 | 1 )]