Sie sind auf Seite 1von 13

Unit testing with SQL Server Data Tools

This is the second part on the serie about SSDT and database development

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.

Unit testing with SQL Server Data Tools by <a href=Régis 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 auto- generate 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. " id="pdf-obj-0-28" src="pdf-obj-0-28.jpg">

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 auto- generate 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

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 1: Getting the latest version of SSDT When checking for updates you also have the

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 project’s 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

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,

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

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:

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

1

CREATE PROCEDURE [dbo].[uspRankCustomers]

2

AS

3

DECLARE @CustomerId int

4

DECLARE @OrderTotal money

5

DECLARE @RankingId int

6

7

DECLARE curCustomer CURSOR FOR

8

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

9

FROM dbo.Customer AS c

1

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

0

Group BY c.CustomerId

1

1

OPEN curCustomer

1

FETCH NEXT FROM curCustomer INTO @CustomerId, @OrderTotal

2

1

WHILE @@FETCH_STATUS = 0

3

BEGIN

1

IF @OrderTotal = 0 SET @RankingId = 1

4

ELSE IF @OrderTotal < 100 SET @RankingId = 2

1

ELSE IF @OrderTotal < 1000 SET @RankingId = 3

5

ELSE IF @OrderTotal < 10000 SET @RankingId = 4

1

ELSE SET @RankingId = 5

6

7

1

8

1

9

2

0

2

1

2

2

2

3

SET RankingId = @RankingId WHERE CustomerId = @CustomerId

2

4

2

FETCH NEXT FROM curCustomer INTO @CustomerId, @OrderTotal END

5

2

6

CLOSE curCustomer DEALLOCATE curCustomer

2

7

2

8

2

9

3

0

3

1

3

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!

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

1

2

3

-- database unit test for dbo.uspRankCustomers DECLARE @RC AS INT;

4

5

 

SELECT @RC = 0;

6

7

8

-- execute the stored procedure EXECUTE @RC = [dbo].[uspRankCustomers] ;

9

1

0

-- select the customer ids without any ranking (should be 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 6: Writing the unit test Step 2: Running the test In the Test tab click

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 we’ll 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 !!

If you remember the previous post in this series, I made it possible to do continuous

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.

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

Using Test Conditions in SQL Server Unit Tests In a SQL Server unit test, one orSqlExecutionResult 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. " id="pdf-obj-11-30" src="pdf-obj-11-30.jpg">

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

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

ResultSet

Execution

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

Time

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

Expected

Fails if the columns and data types of the result set do not match those specified for the test condi

Schema

Inconclusi

Always produces a test with a result of Inconclusive. This is the default condition added to every

ve

condition from your test after you have added other test conditions.

Not Empty

Fails if the result set is empty. You can use this test condition or the EmptyResultSet with the Tra

ResultSet

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

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

Value