Here is a short cookbook showing you the steps you can follow in writing and organizing your own tests using TSQLUnit.
Automatized tests are one of the cornerstones of a methodology called extreme programming, which tries to solve many of the traditional problems with software development. You can read more about it at http://www.xprogramming.org/ or http://www.extremeprogramming.org/.
When you need to test something, here is what you do:
CREATE PROCEDURE ut_testCapitalize AS BEGIN DECLARE @outStr VARCHAR(500) EXEC capitalize 'a string', @outStr OUT IF (ASCII(LEFT(@outStr,1)) <> ASCII('A')) OR @outStr IS NULL EXEC tsu_failure 'Capitalize should make the first character uppercase' END
In addition to this test I would also recommend that you make more tests of the capitalize procedure. You could test what happens when the input is NULL, that the procedure works if there are more than one sentence in the string and so on. When you make many similar tests they often use the same code to populate tables and other input data. In these cases you could create a Fixture.
Suppose you have three tests, ut_CapitalizeOneSentence, ut_CapitalizeWithNull and ut_testCalcSalesForAllCustomers. Since the first two are related you want to make a separate test suite for them which you can run separately from the long running third test. Just rename them ut_capitalizeTests_oneSentence and ut_capitalizeTests_withNull and there you have it, a test suite called "capitalizeTests". If you want to run both test in this suite, execute tsu_runTests 'capitalizeTests'.
Many tests needs to have quite a lot of prepared data as a background. The background is called a test fixture. The fixture can often be shared between similar testcases. This can make the testcode shorter and clearer. In TSQLUnit you can add a fixture to a test suite by creating a special procedure called "setup". The setup procedure will be executed before each test in the testsuite. The setup procedure and the test procedure are executed in a transaction that is rolled back, so you need not be concerned about the order in which the test execute. There is no risk that a previously executed test changes the fixture.
To add a fixture to the "CapitalizeTests" test suite, create a stored procedure called ut_capitalizeTests_setup.
If you have the need to explicitly clean up something that is not automatically rolled back, you can make a stored procedure called "teardown". In this example i should be named ut_capitalizeTests_teardown. An example of where a teardown procedure can be useful is if you create a file in the setup procedure. It will not be removed because the transaction is rolled back, so you will have to delete it in the teardown procedure.
Here is a longer example of how a setup procedure may used. We want to test that the procedure SalesByCategory in the Northwind database calculates the sales figures correctly both with and without a discount. Two testcases are needed for this. The query in the SalesByCategory procedure uses data from four tables, and we can use a fixture to populate them with the data that is needed as a common background for our testcases. Pseudocode for the procedures are below, complete code can be found here.
CREATE PROCEDURE ut_salesbycategory_setup AS BEGIN -- 1. Remove foreign key constraints related to for the tables Categories, Products and Orders. -- This makes it easier to clear the tables and insert testdata. -- 2. Delete all existing data for the tables Categories, Products and Orders. -- 3. Insert one row of test data for each table END CREATE PROCEDURE ut_salesbycategory_noDiscount AS BEGIN -- 1. Create a variable @ok that will hold the result of the test. -- 2. Clear all data from the table [Order Details]. -- Insert a new row in [Order Details] with UnitPrice=100 and Quantity=10 -- 3. Execute SalesByCategory -- 4. If the returned TotalPurchase is 1000 (UnitPrice*Quantity), set @ok to 1 -- 5. If @ok is zero, Execute tsu_failure END CREATE PROCEDURE ut_salesbycategory_discount AS BEGIN -- Do exactly as ut_salesbycategory_noDiscount, but add a discount of 30 percent -- to the row in [Order Details]. Test that SalesByCategory is 700 (70 percent of 1000). END
Test one feature only per test procedure.
Be careful of how the T-SQL comparision operators work when an expression is null. The pattern for the @ok variable in the procedure ut_salesbycategory_noDiscount above solves some problems with this, since it returns a failure in all cases except when the test is correct.
Refactor your testcases when the number of testcases grows. Make sure you understand what they do.
When it is difficult to write tests it can be a sign that you should change the design of the interface or refactor your system.
Do not run your tests in a production system. Even if TSQLUnit should rollback all changes made by the test procedures, you can never know for sure. Until we live in a world free of bugs, be careful of this. If you feel like being dangerous, you should make a backup before you run tests, or better run you tests in a copy of the database.