2014-10-16 60 views
1

我對tSQLt非常陌生,並且在真正應該做一個非常簡單的測試時遇到了一些困難。tSQLt - 測試某列是否由存儲過程輸出

我在存儲過程中執行的SELECT語句中添加了一列。

如何在tSQLt測試中測試該列是否包含在該存儲過程的結果集中?

回答

4

通常,在向存儲過程的輸出添加一列時,您需要測試該列是否存在並且填充了正確的數據。因爲我們要確保該列中填充了相同的數據,我們可以設計一個測試,正是這麼做的:

CREATE PROCEDURE MyTests.[test stored procedure values MyNewColumn correctly] 
AS 
BEGIN 
    -- Create Actual and Expected table to hold the actual results of MyProcedure 
    -- and the results that I expect 
    CREATE TABLE MyTests.Actual (FirstColumn INT, MyNewColumn INT); 
    CREATE TABLE MyTests.Expected (FirstColumn INT, MyNewColumn INT); 

    -- Capture the results of MyProcedure into the Actual table 
    INSERT INTO MyTests.Actual 
    EXEC MySchema.MyProcedure; 

    -- Create the expected output 
    INSERT INTO MyTests.Expected (FirstColumn, MyNewColumn) 
    VALUES (7, 12); 
    INSERT INTO MyTests.Expected (FirstColumn, MyNewColumn) 
    VALUES (25, 99); 


    -- Check that Expected and Actual tables contain the same results 
    EXEC tSQLt.AssertEqualsTable 'MyTests.Expected', 'MyTests.Actual'; 
END; 

一般來說,存儲過程,你是測試依賴於存儲的其他表或其他程序。因此,您應該熟悉FakeTable和SpyProcedure:http://tsqlt.org/user-guide/isolating-dependencies/

+0

謝謝丹尼斯。我認爲我試圖通過專注於一個新的列來複雜化問題,但是通過測試過程的輸出,該列將在默認情況下進行測試 – Neil 2014-10-20 08:13:00

0

如果您只是對輸出結構感興趣而不是內容(並且您在SQL2012或更高版本上運行),另一種選擇是使用sys.dm_exec_describe_first_result_set_for_object在你的測試中。

此dmo(動態管理對象)返回關於爲給定對象返回的第一個結果集的各種信息。

在我下面的例子中,我只使用了這個dmo返回的一些列,但是如果你的輸出包含十進制數據類型,那麼其他列就可用。

在此測試中,我使用關於如何返回每列的信息(例如名稱,數據類型和可空性)填充臨時表(#expected)。

然後,我從dmo中選擇等效列到另一個臨時表(#actual)。

最後我用tSQLt.AssertEqualsTable來比較兩個表的內容。儘管我經常寫測試來驗證視圖或表格的結構(使用tSQLt.AssertResultSetsHaveSameMetaData),但我從來沒有發現只需測試過程的結果集合約即可。丹尼斯是正確的,您通常有興趣聲明結果集中的各個列都填充了正確的值,並且在您覆蓋該功能時,您應該已經覆蓋了每一列。

if object_id('dbo.myTable') is not null drop table dbo.myTable; 
go 
if object_id('dbo.myTable') is null 
begin 
    create table dbo.myTable 
    (
     Id int not null primary key 
    , ColumnA varchar(32) not null 
    , ColumnB varchar(64) null 
    ) 
end 
go 
if object_id('dbo.myProcedure') is not null drop procedure dbo.myProcedure; 
go 
create procedure dbo.myProcedure 
as 
begin 
    select Id, ColumnA, ColumnB from dbo.myTable; 
end 
go 

exec tSQLt.NewTestClass @ClassName = 'myTests'; 

if object_id('[myTests].[test result set on SQL2012+]') is not null drop procedure [myTests].[test result set on SQL2012+]; 
go 
create procedure [myTests].[test result set on SQL2012+] 
as 
begin 
    ; with expectedCte (name, column_ordinal, system_type_name, is_nullable) 
    as 
    (
     -- The first row sets up the data types for the #expected but is excluded from the expected results 
        select cast('' as nvarchar(200)), cast(0 as int), cast('' as nvarchar(200)), cast(0 as bit) 
     -- This is the result we are expecting to see 
     union all select 'Id', 1, 'int', 0 
     union all select 'ColumnA', 2, 'varchar(32)', 0 
     union all select 'ColumnB', 3, 'varchar(64)', 1 
    ) 
    select * into #expected from expectedCte where column_ordinal > 0; 

    --! Act 
    select 
      name 
     , column_ordinal 
     , system_type_name 
     , is_nullable 
    into 
     #actual 
    from 
     sys.dm_exec_describe_first_result_set_for_object(object_id('dbo.myProcedure'), 0); 

    --! Assert 
    exec tSQLt.AssertEqualsTable '#expected', '#actual'; 
end 
go 
exec tSQLt.Run '[myTests].[test result set on SQL2012+]' 
+0

非常感謝您的詳細回覆,但不幸的是我們仍然在爲此項目使用2008 R2。 – Neil 2014-10-17 16:23:49