28
UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Embed Size (px)

Citation preview

Page 1: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

UNIT TESTINGFOR SQL

Prepared for SUGSA CodeLabs

Alain King

Paul Johnson

Page 2: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 2

Why?

Simply put, we want quality!

Page 3: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 3

How

• KRS is committed to Behaviour Driven Development (BDD), i.e. using stories and scenarios to drive development.

• With most of the newer technologies, these scenarios turn into unit tests, either in MSTest, Nunit, Junit, and others

Page 4: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 4

…But…

• We also have big, complex legacy systems that have served us well for many years…

• …and these are mostly written using MS SQL Server stored procedures…

• …and yet we still demand quality, robust, elegant solutions…

Page 5: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 5

…And…

• Clients have invested in high-end servers to host the database so we want to harness that power for large processing tasks (like month end processes)…

• … and there are a number of functions that happen through SQL code in the BI environment (like the ETL process) …

Page 6: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 6

Now what?

• How do you safely add new database functionality?

• How do you safely refactor existing stored procedures/functions?

…without breaking the existing system…

Page 7: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 7

Introducing tSQLt

• tSQLt is a database unit testing framework for Microsoft SQL Server.

• tSQLt is compatible with SQL Server 2005 (service pack 2 required) and above on all editions.

• tSQLt allows you to implement unit tests in T-SQL.

• This is important as you do not have to switch between various tools to create your code and your unit tests.

Page 8: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 8

tSQLt Features

• Tests are automatically run within transactions – this keeps tests independent and reduces any cleanup work you need

• Tests can be grouped together within a schema – allowing you to organize your tests and use common setup methods

• Output can be generated in plain text or XML – making it easier to integrate with a continuous integration tool

• Provides the ability to fake tables and views, and to create stored procedure spies – allowing you to isolate the code which you are testing

Page 9: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 9

Examples

Lets look at some sample code• Write a test for a new stored proc

Page 10: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 10

Examplesbegin tran

select * from Person.Person where BusinessEntityID = 2

BusinessEntityID PersonType NameStyle Title FirstName MiddleName LastName 2 EM 0 NULL Terri Lee Duffy

declare @BusinessEntityID int, @MiddleName varchar(50) select @BusinessEntityID = 2, @MiddleName = 'Leigh'

update Person.Person set MiddleName = @MiddleName where BusinessEntityID = @BusinessEntityID select * from Person.Person where BusinessEntityID = 2

BusinessEntityID PersonType NameStyle Title FirstName MiddleName LastName 2 EM 0 NULL Terri Leigh Duffy

rollback transaction

select * from Person.Person where BusinessEntityID = 2

BusinessEntityID PersonType NameStyle Title FirstName MiddleName LastName 2 EM 0 NULL Terri Lee Duffy

Page 11: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 11

Examplesselect * from Person.Person where BusinessEntityID = 2

BusinessEntityID PersonType NameStyle Title FirstName MiddleName LastName 2 EM 0 NULL Terri Lee Duffy

begin tran

declare @BusinessEntityID int, @MiddleName varchar(50) select @BusinessEntityID = 2, @MiddleName = 'Leigh'

exec Person.uspUpdatePersonInfo @BusinessEntityID = @BusinessEntityID, @MiddleName = @MiddleName select * from Person.Person where BusinessEntityID = 2

BusinessEntityID PersonType NameStyle Title FirstName MiddleName LastName 2 EM 0 NULL Terri Leigh Duffy

rollback transaction

-- check that data is back to originalselect * from Person.Person where BusinessEntityID = 2

BusinessEntityID PersonType NameStyle Title FirstName MiddleName LastName 2 EM 0 NULL Terri Lee Duffy

Page 12: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 12

Examplesexec tSQLt.NewTestClass 'TestPerson'godrop proc TestPerson.[test Person middle name updated correctly]gocreate proc TestPerson.[test Person middle name updated correctly]asbegin declare @BusinessEntityID int, @MiddleName varchar(50) select @BusinessEntityID = 2, @MiddleName = 'Leigh'

-- When I update the MiddletName declare @retval int exec @retval = Person.uspUpdatePersonInfo @BusinessEntityID = @BusinessEntityID, @MiddleName = @MiddleName declare @ActualMiddleName varchar(50) select @ActualMiddleName = middlename from Person.Person where BusinessEntityID = @BusinessEntityID exec tSQLt.AssertEqualsString @MiddleName, 'broken' end

exec tSQLt.RunAll

Page 13: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 13

Examplesexec tSQLt.RunAll

[TestPerson].[test Person middle name updated correctly] failed: Expected: <Leigh> but was: <broken> +----------------------+|Test Execution Summary|+----------------------+ |No|Test Case Name |Result |+--+--------------------------------------------------------+-------+|1 |[TestPerson].[test Person middle name updated correctly]|Failure|-----------------------------------------------------------------------------Msg 50000, Level 16, State 10, Line 1Test Case Summary: 1 test case(s) executed, 0 succeeded, 1 failed, 0 errored.-----------------------------------------------------------------------------

Page 14: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 14

Examples

• Write a test for a new stored proc

• So what did I do wrong?

• Test First

Page 15: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 15

Examples

Scenario

Given Person with ID 2 and Middle Name of Lee

When I update the Middle Name to be Leigh

Then the Middle Name for Person with ID 2 should be Leigh

Page 16: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 16

Examples

Write a test for a new stored proc

• Lets have a look at some code

Page 17: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 17

Examples

• Write a test to compare 2 result sets

• Upgrading legacy systems to be 2008 / 2012 compliant

• Replacing complex queries with CTE’s to be easier to maintain

• In both cases, you are making changes to code and the expect result should be same

Page 18: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 18

Examples

• Write a test to compare 2 result sets

• We can check this by writing a test to output the results from the original code into one table and the results of the modified code into another table and comparing them.

• But we don’t just want to compare for one set of inputs

Page 19: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 19

Examples

• Write a test to compare 2 result sets

• JUnit and NUnit have TestCase functionality that allows one to run the same test with just supplying inputs and expected results as parameters.

Page 20: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 20

ExamplesEXEC tSQLt.NewTestClass 'test_BillingReports';GO

/* ----------------------------------------------------------------------------- */create procedure test_BillingReports.[test periodbilling (@periodno 201101).]asbegin exec test_BillingReports.periodbilling_sub 201101end;

/* ----------------------------------------------------------------------------- */create procedure test_BillingReports.[test periodbilling (@periodno 201201).]asbegin exec test_BillingReports.periodbilling_sub 201201 end;

/* ----------------------------------------------------------------------------- */create procedure test_BillingReports.[test periodbilling (@periodno 201202).]asbegin exec test_BillingReports.periodbilling_sub 201202 end;

Page 21: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 21

Examplescreate procedure test_BillingReports.periodbilling_sub(@periodno int)asbegin if object_id('actual') is not null drop table actual; if object_id('expected') is not null drop table expected;

------Assertion create table actual ( columns )

create table expected ( columns )

--OtherDatabase has the original version of the sproc insert expected ( columns ) exec OtherDatabase..periodbilling @periodno = @periodno

insert actual ( columns ) exec periodbilling @periodno = @periodno

exec tSQLt.assertEqualsTable 'expected', 'actual'; end;go

EXEC tSQLt.run 'test_BillingReports';

Page 22: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 22

Examples

• Write a test to compare 2 result sets

• Lets take a look at some more code

Page 23: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 23

Examples

• Write a test for an existing stored procedure

• This can be used for DDT – Defect Driven Testing or for enhancing existing functionality.

• Lets look at a test for an existing procedure in AdventureWorks called uspGetEmployeeManagers

Page 24: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 24

Exercises

• Download from tsqlt.org

• exec tSQLt.NewTestClass 'TestPerson'• Go

• create proc TestPerson.[test UpdatePersonMiddleName]• as

• exec tSQLt.AssertEqualsString @MiddleName, @ActualMiddleName

• end

• exec tSQLt.RunAll

Page 25: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 25

Exercises

• Write a test for a new stored procedure to check if an email address already exists in the database

Page 26: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 26

Exercises

• Write a test for a new stored procedure to update available leave hours for an employee

Page 27: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

Unit Testing for SQL 27

Exercises

• We want to make changes to an existing stored procedure, write a test for uspGetBillOfMaterials to ensure that any changes you make do not have a negative impact on existing functionality.

Page 28: UNIT TESTING FOR SQL Prepared for SUGSA CodeLabs Alain King Paul Johnson

28

Questions?

www.krs.co.za

( (021) 681 2900Alain King: [email protected] Johnson: [email protected]

Unit Testing for SQL