Unit Test - Part 2 (tSQLt)

March 28, 2016

 

היי חברים,

 

בהמשך למאמר הקודם Database Unit Testing with Visual Studio שבו הוצג כיצד ניתן לכתוב בדיקות לקוד ע"י Visual Studio, הפעם אציג תשתית דיי ותיקה ונפוצה בתחום Database Unit Test בשם tSQLt.

 

רקע:

tSQLt הינה תשתית Open Source חינמית שנתמכת מגרסה - SQL Server 2005 SP2 והוקמה ע"י:

1.  DR. SEBASTIAN MEINE (Blog|Twitter)

2. DENNIS LLOYD JR.(Blog)

 

בדומה למאמר הראשון, גם במאמר זה כל הבדיקות יבוצעו מול מסד נתונים AdventureWorks כאשר הוספתי לו ניפוח שניתן להוריד מכאן.

 

 

 

PREREQUISITES:

  • הורד את הקוד של הקמת התשתית מכאן.

  • וודא\אשר הרצת אוביקטים מסוג clr בשרת

EXEC sp_configure 'clr enabled', 1;

 

RECONFIGURE;

  • אשר ברמת מסד הנתונים –

ALTER DATABASE AdventureWorks SET TRUSTWORTHY ON;

  • כעת הרץ את הסקריפט - tSQLt.class.sql מתוך הסקריפטים שהורדת מהאתר.

הערה: את ההתקנות מומלץ לבצע על שרת בדיקות/ פיתוח/ אינטגרציה ולא על שרתי ייצור.

הקובץ - tSQLt.class.sql ייצר אובייקטים לטובת בניית התשתית בתוך מסד הנתונים.

 

שימוש בקוד:

תחילה, יש ליצור Class (סכמה) לטובת הקמת הבדיקות

EXEC tSQLt.NewTestClass 'Demo';

קיימות מספר דרכים להריץ בדיקות דרך התשתית-

הרצת כל הסכמות(Class) המקושרות לתשתית -

EXEC tSQLt.RunAll;

הרצת כל הבדיקות הקשורות לסכמה שבחרנו -

EXEC tSQLt.Run 'Demo';

EXEC tSQLt.RunTestClass 'Demo';

הרצת בדיקה ספציפית -

DECLARE @TestName nvarchar(max) = '[Demo].[test_Exception_table_exists]'

 

EXECUTE [tSQLt].[Run] @TestName

בגלל שהתשתית זכתה לאהדה רבה בקרב המפתחים (לרוב זה קורה כאשר יש כלי מעולה והוא חינמי) חברת Red-Gate כתבה מוצר משלים לתשתית אשר מספק ממשק שמתחבר לSSMS.

המוצר עצמו – SQL Test אמנם עולה כסף, אך למי שמשתמש בתשתית על בסיס יומי\ קבוע יימצא לוודאי את הכדאיות בתשלום הנוסף.

דרך נוספת להרצה: דרך הUI  ע"י תוסף SQL Test -

כתיבת הבדיקות:

נתחיל עם בדיקה קלה יחסית כדי לוודא שהשכל עובד בצורה תקינה –

נקים בדיקה חדשה –

CREATE PROCEDURE [Demo].[testSimpleTest]

AS

BEGIN

    DECLARE @TestingSUM INT;

    SELECT @TestingSUM = 1 + 1;

    EXEC tSQLt.AssertEquals 2, @TestingSUM

END;

הערה: כל בדיקה חייבת להתחיל במילה test. אחרת היא לא תרוץ.

 

נריץ את הבדיקה וניראה אם היא עברה בהצלחה.

הפלט:

+----------------------+

|Test Execution Summary|

+----------------------+

 

|No|Test Case Name         |Dur(ms)|Result |

+--+-----------------------+-------+-------+

|1 |[Demo].[testSimpleTest]|      3|Success|

-----------------------------------------------------------------------------

Test Case Summary: 1 test case(s) executed, 1 succeeded, 0 failed, 0 errored.

-----------------------------------------------------------------------------

ניתן לראות בפלט את הבדיקה שהרצנו מתוך סל הבדיקות ואת הסיכום הסופי.

בנוסף, ניתן לראות את משך הזמן שלקח לה לרוץ והאם הבדיקה עברה בהצלחה.

בשורת הסיכום ניתן לראות את סך הבדיקות שהרצנו ע"פ סיכום של הצלחה, כישלון ושגיאה.

 

לצורך בדיקה, נוודא שהבדיקה נופלת במקרה שהכנסנו טעות בכוונה – את החישוב השארנו על 1 + 1 אך, את התוצאה הצפויה שינינו ל-8.

CREATE PROCEDURE [Demo].[testSimpleTest_Failed]---testing simple UTC]

AS

BEGIN

    DECLARE @TestingSUM INT;

    SELECT @TestingSUM = 1 + 1;

    EXEC tSQLt.AssertEquals 8, @TestingSUM

END;

הפלט:

[Demo].[testSimpleTest_Failed] failed: (Failure) Expected: <8> but was: <2>

 

+----------------------+

|Test Execution Summary|

+----------------------+

 

|No|Test Case Name                |Dur(ms)|Result |

+--+------------------------------+-------+-------+

|1 |[Demo].[testSimpleTest_Failed]|      0|Failure|

-----------------------------------------------------------------------------

Msg 50000, Level 16, State 10, Line 13

Test Case Summary: 1 test case(s) executed, 0 succeeded, 1 failed, 0 errored.

-----------------------------------------------------------------------------

כעת ניתן לראות שהבדיקה נכשלה, בשורה הראשונה של הפלט התשתית כתבה לנו שהיא ציפתה ל-8 ותוצאת החישוב יצאה 2.

 

ניראה שמה שציפינו בוצע בהצלחה, אבל מה הרצנו?

כאשר אנו מתקינים את התשתית אנו מקבלים כלים שמאפשרים לנו לבצע מספר רב של בדיקות מסוגים שונים.

אנו הרצנו כלי - tSQLt.AssertEquals אשר מקבל 2 פרמרטים חובה ואפשרות לפרמטר נוסף –

tSQLt.AssertEquals [@expected = ] expected value

                 , [@actual = ] actual value

                [, [@message = ] 'message' ]

הכלי מאפשר לנו להשוות בין 2 תוצאות מסוג SQL_VARIANT.

  • Assertions

    • AssertEmptyTable – בודק האם טבלה ריקה מערכים

    • AssertEqualsString – בודק בין 2 ערכי טקסט

    • AssertEqualsTable – משווה ערכים בין 2 טבלאות

    • AssertNotEquals – בודק האם 2 ערכים אינם זהים

    • AssertObjectDoesNotExist – בודק האם לא קיים אובייקט במסד הנתונים

    • AssertObjectExists – בודק האם אובייקט קיים במסד הנתונים

    • AssertResultSetsHaveSameMetaData – בודק האם 2 תוצאות זהות ברמת הסכמה

    • Fail – הכשלה מכוונת

וכמובן שיש עוד כלים אשר ניתן לקרוא עליהם בהרחבה באתר...

 

עוד בדיקה שניתן להוסיף היא השוואת ערכים בין 2 טבלאות ע"י שימוש בכלי tSQLt.FakeTable,

הכלי מאפשר ליצור לטובת הScoop של הבדיקה טבלה זהה בשם לטבלה שקיימת במסד הנתונים אך ללא אילוצים. לטובת השוואה נקודתית בין 2 סטים – צפוי וקיים-

 

CREATE PROCEDURE [Demo].[testingAssertEqualsTable]

AS

BEGIN

 

  -- and the results that we expect

  IF OBJECT_ID('actual') IS NOT NULL DROP TABLE actual;

  IF OBJECT_ID('expected') IS NOT NULL DROP TABLE expected;

  DECLARE @Date DATETIME = GETDATE();

 

  ------Fake Table

  EXEC tSQLt.FakeTable '[Sales].[CreditCard]';

 

       INSERT INTO [Sales].[CreditCard]

                    ( [CreditCardID],

                           [CardType] ,

                           [CardNumber] ,

                           [ExpMonth] ,

                           [ExpYear] ,

                           [ModifiedDate]

                    )

       VALUES  ( 1,

                           N'xxx' , -- CardType - nvarchar(50)

                           N'yyy' , -- CardNumber - nvarchar(25)

                           3 , -- ExpMonth - tinyint

                           2016 , -- ExpYear - smallint

                           @Date  -- ModifiedDate - datetime

                    )

 

------Execution

    SELECT [CreditCardID],

                           [CardType] ,

                           [CardNumber] ,

                           [ExpMonth] ,

                           [ExpYear] ,

                           [ModifiedDate]

      INTO actual

      FROM [Sales].[CreditCard];

 

------Assertion

    CREATE TABLE expected (

       [CreditCardID] [int],

       [CardType] [nvarchar](50),

       [CardNumber] [nvarchar](25),

       [ExpMonth] [tinyint],

       [ExpYear] [smallint],

       [ModifiedDate] [datetime]

    );

 

       INSERT INTO expected SELECT 1,

                           N'xxx' , -- CardType - nvarchar(50)

                           N'yyy' , -- CardNumber - nvarchar(25)

                           3 , -- ExpMonth - tinyint

                           2016 , -- ExpYear - smallint

                           @Date  -- ModifiedDate - datetime

                   

 

       EXEC tSQLt.AssertEqualsTable 'expected', 'actual';

 

 

END;

 

הפלט:

 

|No|Test Case Name                   |Dur(ms)|Result |

+--+---------------------------------+-------+-------+

|1 |[Demo].[testingAssertEqualsTable]|    176|Success|

-----------------------------------------------------------------------------

Test Case Summary: 1 test case(s) executed, 1 succeeded, 0 failed, 0 errored.

-----------------------------------------------------------------------------

 

ניתן למצוא עוד הרבה דוגמאות לבדיקות מורכבות ופשוטות לדוגמא ברשת-

  1. Test Driven Database Development with tSQLt – כתבה מכיפה בת 10 חלקים לכל סוגי הבדיקות

  2. אתר המקור שמלא בדוגמאות - USER GUIDE

  3. סרטוני הדרכה שלpluralsight -   Unit Testing T-SQL Code with tSQLt

  4. ספר - Database Unit Testing for SQL Server Using tSQLt

לסיכום:

התשתית מספקת לנו דרך קלה, יעילה והכי חשוב חינמית לכתיבת בדיקות אך, האם יש לנו בעזרת התשתית פתרון שיכול לעזור לנו לבדוק פרוצדורה/ות עם מספר רב של פרמטרים (לא כולם חובה) ועם שילובים שונים של תלות בין הפרמטרים ובין התוכן של כל פרמטר שתוכל למדוד שגיאות וזמני ריצה?

איך אתם עושים זאת היום?

 

יתרונות:

  1. תשתית - כל בדיקה רצה תחת טרנזקציה ולא משאירה אובייקטים שנועדו רק לטובת הבדיקה – ניקוי כל בדיקה בפני עצמה.

  2. תשתית - כל סט של בדיקות רץ תחת קבוצה (Class) או מבחינתנו סכמה.

  3. תשתית - ניהול ע"י T-SQL

  4. UI - אינטגרציה מלאה לSSMS.

  5. UI – תמיכה ב2 תשתיות tSQLt + SQLCop(Not In This Scoop)

חסרונות:

  1. תשתית - מחייב הרשאת clr (חסרון תלוי פרספקטיבה).

    1. TRUSTWORTHY ON

  2. תשתית - מלכלך את מסד הנתונים – משאיר המון אובייקטים במסד הנתונים לטובת ניהול התשתית – מפריע במקרה של השוואת סכמות.

  3. תשתית - לא יודע לבדוק Time Out.

  4. UI – עולה כסף

 

Please reload

Featured Posts

I'm busy working on my blog posts. Watch this space!

Please reload

Recent Posts

October 31, 2017

October 29, 2017

Please reload

Archive
Please reload

Search By Tags