Click here to monitor SSC
Av rating:
Total votes: 8
Total comments: 4


Rob Sullivan
SQL Test: Seeing Red Change to Green
13 December 2011

Now that we have some very good test frameworks for SQL Server, particularly tSQLt, all that was missing was a way of running your unit tests from within SQL Server Management Studio, and 'seeing red change to green'. Now the wait is over, with the arrival of SQL Test in preview. Rob Sullivan is one of those users who are helping shape the way that SQL Test develops, and explains what is going on, and why.

If you are an application developer at an agile shop and spend a good chunk of your time in Visual Studio, you are no doubt familiar with unit testing and Test Driven Development (TDD). There are various tools and frameworks that have been created and have matured over time to make this type of development fun and effective. Part of the reason this is so successful is that languages like C# are incredibly static which contrasts with the highly dynamic nature of databases. This means that a table with 1 row today can have 1M rows tomorrow, execution plans change, and so on. Such complexities are part of the reason why, when it comes to database testing, there have been lots of attempts, frameworks and ultimately failures to scratch this itch. Frameworks such as TSQLUnit have come close to filling the void, but the lack of mocking, object pollution, examples and a fluid test runner not only made this process a hard sale to myself but also to our development process. There is a newer open source testing framework on the rise that is called tSQLt. It has a very nice mocking system. Having talked to one of its creators at the PASS Summit, I know for a fact that these guys completely get and buy into the TDD mantra. There is still something missing though... that handy test runner inside of SQL Server Management Studio (SSMS). This is where our friends over at Red Gate are coming to the rescue again.

So let’s see this tool in action! In the AdventureWorks database, there is this fun little function called [ufnGetContactInformation] which has all sorts of sub queries, conditions and case statements with some magic quoted values. We have just been given a ticket from the business unit saying they need some of the verbiage in the “contract type” changed from ‘Store Contact’ to ‘Kiosk Contact’. Falling in line with the ‘Red then Green’ mantra of testing, we’re going to do the following:

  1. Create a test that checks for the expected result
  2. Run the test and have it go red (fail)
  3. Change our function to reflect the desired business rule
  4. Run the test and step 3 until the test goes green (Winning!)

In the SQL Test window, click on the “+Add Database to SQL Test” link and add Adventure Works to it.

Adding the database

Now that we have our database wired up, it is time to click “+ New Test” in the SQL Test window and fill out the modal that pops up.

The pop-up modal

As you can see in the image, we put our test name in, confirm our database and put in a test class. The test classes will help isolate our various test suits into their own schema. As soon as we click ‘Create Test’ we are created with a nice test skeleton that gives us the 3 pillars of a test: Assemble - Act - Assert.

Our test:

ALTER PROCEDURE [ContactInformationFunction].[test Make Sure Contact Type is Correct]
AS
BEGIN

--Assemble. This is where we will be mocking our data using fake tables with fake data sets.
EXEC tSQLt.FakeTable 'Person.Contact';
INSERT INTO Person.Contact (ContactID, FirstName, LastName)
VALUES (1,'Rob','Sullivan');
EXEC tSQLt.FakeTable 'Person.Contacttype';
INSERT INTO Person.Contacttype (ContacttypeID, Name, ModifiedDate)
VALUES (11,'Owner',GETDATE());
EXEC tSQLt.FakeTable 'Sales.StoreContact';
INSERT INTO Sales.StoreContact (CustomerID, ContactID, ContactTypeID, RowGuid,ModifiedDate)
VALUES (1, 1, 11, NEWID(), GETDATE());

--Act: Here we are running our function against our fake tables and logging the results.
SELECT [ContactType]
INTO #Actual
FROM [ufnGetContactInformation] (1)
--Assert: Create the table/schema for the expected
SELECT TOP(0) * INTO #Expected FROM #Actual;

-- Per ticket #2314 we need Contract to return Kiosk Contract
-- when they exist in the [Sales].[StoreContact]
INSERT INTO #Expected ([ContactType]) VALUES ('Kiosk Contact');

-- Let's see if everything adds up correctly. We are automating our confidence.
EXEC tSQLt.AssertEqualsTable '#Expected', '#Actual';
END;

We use our handy hot key of Alt + shift + x to run our tests right in management studio and as expected, our test fails. Now we just need to hop into the function itself and change the section of code dealing with the Store Contact to Kiosk Contact:

WHEN EXISTS(SELECT * FROM [Sales].[StoreContact] sc
INNER JOIN [Person].[ContactType] ct
ON sc.[ContactTypeID] = ct.[ContactTypeID]
WHERE sc.[ContactID] = @ContactID)
THEN 'Store Contact'

Will turn into:

WHEN EXISTS(SELECT * FROM [Sales].[StoreContact] sc
INNER JOIN [Person].[ContactType] ct
ON sc.[ContactTypeID] = ct.[ContactTypeID]
WHERE sc.[ContactID] = @ContactID)
THEN 'Kiosk Contact' -- fixed for ticket 2314

After we make the change, we run our test again and it passes and we look like heroes. Not only do we look like heroes, we have created living documentation of our database so that the noob 8 months from now who has to change it back to ‘Store Contact’ will hopefully already have a nice set of tests to help him make the change with confidence.

Cons:

  • The tSQLt framework will completely litter your database with its objects. (but it does have a nice uninstaller if the objects trigger your OCD too much).
  • The SQL Test tool has a few quirks as it is quite early in its build process.
  • The dynamic nature of how we get data makes traditional unit testing like you see with C#(incredibly static) a bit trickier.
  • This is a fairly new and unexplored space. It can be hard to see the value in unit testing until you have really bought in and it saved your bacon.

Pros:

  • Huge amount of potential in this space to change how we do things or to automate our code confidence.
  • The team is listening to feed back and you see with the quick iterations. There have already been 3 new builds fixing issues since I started playing with it the other day.
  • tSQLt (or other frameworks when they are supported) provide nice hooks for your continuous integration server.
  • While it is married to the tSQLt framework right now, as this space picks up heat, one would assume that Red Gate’s SQL Test would become a test runner for various frameworks in the same manner that SQL Source Control hooks you up with various source control providers.
  • It brings to you unit testing in a language you know... T-SQL

Resources



This article has been viewed 4334 times.
Rob Sullivan

Author profile: Rob Sullivan

Rob is a bona fide Alpha Nerd, SQL Server DBA by day and code slinger by night. He is also the token DBA on This Developers Life, SQL Dude for Tekpub, open source contributor to .NET Micro ORMS and speaker. He is an active member of the Oklahoma City Developers Group and founder/officer of his beloved Oklahoma City SQL Server Developers Group.

Search for other articles by Rob Sullivan

Rate this article:   Avg rating: from a total of 8 votes.


Poor

OK

Good

Great

Must read
 
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: DB Intrusion
Posted by: Anonymous (not signed in)
Posted on: Wednesday, December 21, 2011 at 8:35 AM
Message: I would not use a product that disturbs the state of an existing database. Not sure why this would or could be an accepted pattern for testing. Also how does Red-Gates SQL Source Control react to this. Appears like this would add a tremendous amount of over-head in management of the DB's under test, etc.

Subject: Schema's and stuff
Posted by: Rob Sullivan (view profile)
Posted on: Wednesday, December 21, 2011 at 9:04 AM
Message: With regards to SQL Source Control, you can just create a filter for the TSQLT objects. Likewise, since all the TSQLT objects are locked in to the TSQLT schema, I don't find the management to be that hard.

Subject: How SQL Source Control works with SQL Test
Posted by: David Atkinson (view profile)
Posted on: Wednesday, December 21, 2011 at 9:58 AM
Message: SQL Source Control just sees the tSQLt framework and the tests as new objects. An approach would be to *not* use a SQL Source Control filter and commit the framework and tests to source control. This provides an elegant mechanism to share unit tests among developers. Upon deployment you would use a SQL Compare filter to ensure the framework and tests don't get pushed to Production.

Subject: Intrusion or Inclusion?
Posted by: Bill Nicolich (not signed in)
Posted on: Thursday, December 22, 2011 at 9:16 AM
Message: For sure you want tests to go in a separate schema. The Redgate tool does that. Not so with TSQLUnit at the time I vetted it.

There's an analogy with solutions in Management Studio. One adds a test project to the same solution as a separate project. Here, you add a testing schema to the same database.

For me, I want the tests to go with the code to source control. I see it as a good thing.

 










Phil Factor
Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL Server... Read more...



 View the blog
SQL Source Control: The Development Story
 Often, there is a huge difference between software being easy to use, and easy to develop. When your... Read more...

How to Import Data from HTML pages
 It turns out that there are plenty of ways to get data into SQL Server from websites, whether the data... Read more...

SQL Scripts Manager: An Appreciation
 SQL Scripts Manager is Simple-Talk's present to its readers. William Brewer was an enthusiastic... Read more...

Hosted Team Foundation Server 2010 Review
 Team Foundation Server (TFS) has expanded its remit to support the whole software development process,... Read more...

The Parodist: A SQL Server Application
 Every year, we ask Phil Factor to celebrate the holiday season with an article on SQL Server... Read more...

Beginning SQL Server 2005 Reporting Services Part 1
 Steve Joubert begins an in-depth tour of SQL Server 2005 Reporting Services with a step-by-step guide... Read more...

Ten Common Database Design Mistakes
 Database design and implementation is the cornerstone of any data centric project (read 99.9% of... Read more...

Reading and Writing Files in SQL Server using T-SQL
 SQL Server provides several "standard" techniques by which to read and write to files but, just... Read more...

Beginning SQL Server 2005 Reporting Services Part 2
 Continuing his in-depth tour of SQL Server 2005 Reporting Services, Steve Joubert demonstrates the most... Read more...

Creating CSV Files Using BCP and Stored Procedures
 Nigel Rivett demonstrates some core techniques for extracting SQL Server data into CSV files, focussing... Read more...

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.

Join Simple Talk