Вы находитесь на странице: 1из 13

Unit testing with SQL Server Data Tools

by Rgis Baccaro
This is the second part on the serie about SSDT and database development
Part I: Continuous integration with SQL Server Data Tools and Team Foundation Server

Introduction
In December 2012, a great addition was made to SSDT: The ability to do database unit
testing.
However, this feature is not available on the free edition of SSDT. For doing unit test
with SSDT you will at least need a Visual Studio Professional edition or above.
As you and the team members make changes to the database schema you can verify
that these changes are working as expected or if they have broken existing
functionality.
Please bear over with me making so many screen dumps but I was so fortunate to get a
license of SnagIt from TechSmith so I am also trying the possibilities of the tool in this
blog post.

Proceeding
Usually you will want to baseline your database and then run some unit tests on the
changes that you have made. Personally, I have made a habit out of taking a snapshot
of the database I am working with at different stages and at least once a week. This way
I can always go back to the state it was before I made the subsequent changes without
having to roll back changes with TFS.
Because unit testing of your database is just a Unit Test Project, you can create and
run database unit test without a database project. However, the only way to autogenerate tests for specific database objects is to use the database project.
When creating a test project from a database project Visual Studio will automatically
generate some of classes for you. Most of the plumbing will be done that way. The most
important class in that regard is:
Microsoft.Data.Tools.Schema.Sql.UnitTesting;

Checking for the latest version of SSDT


First you need to check if you have the latest version of SSDT. This is done with
the Check for Updates menu under the SQL menu.

Figure 1: Getting the latest version of SSDT

When checking for updates you also have the possibility to let Visual Studio do it
automatically for you by selecting automatically check for updates to SQL Server
Data Tools.

Figure 2: Automatically checking for new versions

Using Projects in SQL Server Object Explorer


(SSOX)

Each time you hit F5, SSDT will deploy your database to your LocalDB. By the way, it is
possible to change this behavior by going to the Debug tab of the projects property
page and change the connection string there so your database gets deployed
somewhere else than in this local instance.

Creating a SQL Server Unit Test from an


existing object in the database
From SSDT You can automatically create stubs for unit testing stored procedures,
functions and triggers.
Let us say that we want to test a stored procedure called uspRankCustomer that we
created in a previous blog post. See Continuous integration with SQL Server Data Tools
and Team Foundation Server for a script for creating the database. Alternatively,
use this embedded script with the complete database schema used in this example.
Find the stored procedure you want to create the test stub for and right-click on it in the
project node of SSOX (keep in mind that the Projects node will not contain your
database project before you have successfully deployed / publish your database).

Figure 3: Creating unit tests from Projects node

In the window that shows next, you can chose if you want to create a VB.Net or a C#
test project as well as a list of all the database object that support unit testing and the
class name for the test file being created.

Figure 4: Choosing which element to create test for

I chose C# and after project creation, you are presented with a SQL Server Test
Configuration dialog where you can specify which database to run the test on even a
secondary connection to validate those tests as well as the option to deploy the
database prior to you run your tests.
Remark : If you must test views or stored procedures that have restricted permissions,
you would typically specify that connection in this step. You would then specify the
secondary connection, with broader permissions, to validate the test. If you have a
secondary connection, you should add that user to the database project, and create a
login for that user in the pre-deployment script.
In my case I want to run my tests on the database I deployed earlier This is how my
setup looks like:

Figure 5: Configuring the test project

If you look at the solution explorer you will see that following was created:

A test project

A SqlDatabaseSetupFile

A SQLUnitTest class

The app.config of the project contains the settings for deployment and database
connection

Define test logic


My database is quite simple and contains 3 tables and 3 stored procedures. In my
previous post, I created a table and a procedure for ranking customers. I now want to

test if my ranking procedure uspRankCustomers works as intended and ranks the


customer as specified in the ranking table.
Here is the simple stored procedure used:

1 CREATE PROCEDURE [dbo].[uspRankCustomers]


2 AS
3

DECLARE @CustomerId int

DECLARE @OrderTotal money

DECLARE @RankingId int

6
7

DECLARE curCustomer CURSOR FOR

SELECT c.CustomerID, ISNULL(SUM(oh.OrderTotal), 0) AS OrderTotal

FROM dbo.Customer AS c

LEFT OUTER JOIN dbo.OrderHeader AS oh ON c.CustomerID = oh.CustomerID

Group BY c.CustomerId

1
1

OPEN curCustomer

FETCH NEXT FROM curCustomer INTO @CustomerId, @OrderTotal

2
1

WHILE @@FETCH_STATUS = 0

BEGIN

IF @OrderTotal = 0 SET @RankingId = 1

ELSE IF @OrderTotal < 100 SET @RankingId = 2

ELSE IF @OrderTotal < 1000 SET @RankingId = 3

ELSE IF @OrderTotal < 10000 SET @RankingId = 4

ELSE SET @RankingId = 5

6
1

UPDATE Customer

7
1
8
1
9
2
0
2
1
2
2
2
SET RankingId = @RankingId
3
WHERE CustomerId = @CustomerId
2
4
FETCH NEXT FROM curCustomer INTO @CustomerId, @OrderTotal
2
END
5
2
CLOSE curCustomer
6
DEALLOCATE curCustomer
2
7
2
8
2
9
3
0
3
1
3
2

Test: For my existing customers I want to update the ranking using the Ranking table.

Step 1: Define the test script


I want to execute my stored procedure and make sure that there are no nulls in the
rankingID of the customer table. This way I can be sure that all customers have been
ranked!

1
2
-- database unit test for dbo.uspRankCustomers
3
DECLARE @RC AS INT;
4
5
SELECT @RC = 0;
6
7
-- execute the stored procedure
8
EXECUTE @RC = [dbo].[uspRankCustomers] ;
9
1
-- select the customer ids without any ranking (should be 0)
0
SELECT @RC = CustomerID from Customer where RankingID IS NULL
1
1
SELECT @RC AS RC;
1
2

In Test conditions delete the automatically created condition and create a new one.
Change its type to Scalar Value and in the property window make sure the expected
value is 0.

Figure 6: Writing the unit test

Step 2: Running the test


In the Test tab click Windows and then Test Explorer the Test Explorer window should
appear, listing your test. Right-click on it and choose Run Selected Test. It should now
run and show a green icon if it a success (or a red one in event of a failure).

Figure 7: Successful test run

If you remember the previous post in this series, I made it possible to do continuous
deployment with MSBuild and Team Foundation Server. I showed how you are able to
build and deploy your database changes for each check-in. Well, it is also possible to
have this procedure run the test for you. This is useful for running automated tests and
analyze the impact of code changes on your tests as part of your build process.
But for now well disable it by removing it in the Build Definition file. On the left pane
choose Process and Click the ellipsis on the right side of Automated Test and
click Remove in the dialog that shows !!

Figure 8: Removing test from build process

Running test as a part of your Build Process will be the subject of upcoming blog posts,
so stay tuned for more SSDT and unit testing fun!!

Using Test Conditions in


SQL Server Unit Tests
In a SQL Server unit test, one or more Transact-SQL test scripts are executed. The results
can be evaluated within the Transact-SQL script and THROW or RAISERROR used to return an
error and fail the test, or test conditions can be defined in the test to evaluate the results.
The test returns an instance of the SqlExecutionResult class. The instance of this class
contains one or more DataSets, the execution time, and the rows affected by the script. All
of this information is collected during execution of the script. These results can be evaluated
by using test conditions. SQL Server Data Tools provides a set of predefined test conditions.
You can also create and use custom conditions; see Custom Test Conditions for SQL Server
Unit Tests.

Predefined Test Conditions


The following table lists the predefined test conditions that you can add by using the Test
Conditions pane in the SQL Server Unit Test Designer.

Test
Condition

Data
Checksum

Test Condition Description

Fails if the checksum of the result set returned from the Transact-SQL script does not match the e

Note

This test condition is not recommended if you are returning data that will vary between test runs
the checksum will be different on each run.

Empty
ResultSet

Fails if the result set returned from the Transact-SQL script is not empty.

Execution
Time

Fails if the Transact-SQL test script takes longer than expected to execute. The default execution

The execution time applies to the test script test only, not to the pre-test script or the post-test scri

Expected
Schema

Fails if the columns and data types of the result set do not match those specified for the test condi
see Specifying an Expected Schema.

Inconclusi
ve

Always produces a test with a result of Inconclusive. This is the default condition added to every
condition from your test after you have added other test conditions.

Not Empty
ResultSet

Fails if the result set is empty. You can use this test condition or the EmptyResultSet with the Tran
example, you can save pre-update values, run the update, compare post-update values, and raise a

Row Count

Fails if the result set does not contain the expected number of rows.

Scalar
Value

Fails if a particular value in the result set does not equal the specified value. The default Expected

http://www.sqlshack.com/sql-server-business-intelligence-features-creating-reportsbased-olap-cubes/

Вам также может понравиться