TSQL Unit Test tools 2017: SQL Server Data Tools 2017 vs tSQLt
Asked Answered
C

3

12

I have a new project that needs SQL Server unit test, and CI/CD with VSTS.

Below is the features that are required

  • SQL server unit test against stored procedure, initial target tables setup for each test and clean up

  • Unit test in sql

  • CI/CD with VSTS and Git

  • Easy setup and easy to use

I looked into SSDT 2017, which seems good. But it seems it lacks a feature where common setup script can be shared easily between each test in Pre-Test step. It might lack other features that should be available for daily usage. But I might be wrong.

Which tool fits better for general sql server unit testing in 2017?

SQL Server Data Tools for Visual Studio

TSQLT

Correa answered 17/12, 2017 at 22:21 Comment(4)
tSQLt is the best SQL Server unit testing framework so far. What's the exact problem are you facing?Actuary
I have not looked into tSQLt yet. But I am assuming SSDT will be easier to integrate to CI and VSTS. One of the problem that comes into mind is setup database for unit test on both dev and QA/UAT environment. Ideally, both it allows to ran on memory database which is same as sql server 2014.Correa
tSQLt is quite easy to setup. I am not sure why do you need to run the tests on both environments.Actuary
sorry for the confusion. I meant dev machine and build server. Is there a solution for database? What about feature of reuse of setup script among each test?Correa
E
29

One of the reasons why there aren't more unit testing solutions out there for SQL development is because proper unit testing is inherently harder with databases so people don't do it. This is because databases maintain state and also referential integrity. Imagine writing a unit test for a stored procedure (order_detail_update_status) that updates a status flag on an order_detail table. The order_detail table has a dependency on the order_header and product tables, order_header in turn has foreign keys to customer and employee whilst the product table may depend on product_category, product_type and supplier. That is at least seven tables (probably more) that need to be populated with valid data just to write one test and all but one of those tables have nothing to do with the code under test.

So what you should be looking for in a unit testing solution is exactly that - the ability to test discrete units of code - with the minimum of set-up. So ideally, you would be able to just set up the required test data in order_detail and ignore the rest of the tables - I am aware of only one testing framework that allows you to do that.

Additionally, unit tests should have minimal reasons to fail, in the above example, order_detail_update_status just updates a single row on the order_detail table. If a new not null column is added to the customer table, which is not handled by the test set-up then you have a scenario where our test could fail for a totally unrelated reason. This makes for very brittle tests and, under the pressure of tight delivery deadlines, developers will quickly give up writing and maintaining tests.

A suite of unit tests should be runnable in any order, with no interdependencies and a good test framework should support this along with set-up, tear down and support for mocking objects (which may or may not be part of the same framework). In the above scenario, the ability to mock the order_detail table to test a module that only touches the order_detail table is one of the most important features if you don't want to spend huge amounts of time fixing tests that are failing for no "good" reason.

So in terms of your requirements, and the above points, there is only one framework that I am aware of that does all of this - tSQLt. This is based on real-world experience - we had over 6,000 tSQLt unit tests on my last project. It includes the following feautures:

  • Unit test stored procedures, functions and views
  • Mock tables, views and functions
  • Mock (or spy) stored procedures - either for isolation, replay or pre-defined outcomes
  • Suite set-up
  • Automatic tear-down (as every test runs in it's own translation)
  • Unit tests are completely isolated and can be executed in any order

It works very well with VSTS in a CI/CD and, as all the unit tests are written in T-SQL, it is very easy to use.

The best way to use tSQLt in Visual Studio is to make use of composite projects - where application database objects and modules are maintained in one project whilst the tSQLt framework and all unit tests are part of a second project. There is a good aticle to get you started on this here.

I wrote a more detailed article on the benefits of tSQLt for Simple-Talk a few year back which might also be helpful

Evita answered 18/12, 2017 at 7:28 Comment(2)
whoa, thank you very much for your detailed answer. I will take a look. I hope there is someone like you who have similar depth of experience on SSDT. So I can make a better decision.Correa
@Correa I am doing the same exercise (tSQLt) vs SSDT). Can you share your own conclusion/experience after 4 years?Hawkinson
C
5

Note that Microsoft is promoting slacker, see e.g. Channel 9: SQL Server Database Unit Testing in your DevOps pipeline. We found it to work reasonably well in an Azure SQL setup. For tSQLt on Azure SQL I remember some issues around enabling CLR and TRUSTWORTHY options but also saw that it should still work, e.g. here:

Cairo answered 8/5, 2019 at 15:14 Comment(0)
A
3

You can re-use scripts, you can do a lot of things. Quick answer to your question is just use tSQLt. There is no other unit testing frameworks for SQL Server to be so powerful/flexible and easy to use than tSQLt so far. Just start using and that's it. It is quite easy and quick to setup in SSDT. @datacentricity wrote you enough about that framework and if you are want to know more, then read the article he provided.

I'll just add few things to make your life a bit easier if you'll go tSQLt direction:

  • Use synonyms for all cross database or linked objects;
  • Create all the tSQLt objects using the standard script in SSMS and then import the objects into the SSDT
  • Create separate project for tSQLt objects and mark it as "the same database" as your database you are willing to test
  • Create pre-script in the tSQLt project and run the pre-script of your original database project from there
  • Create post-script in tSQLt project and run the post-script of your original database project from there
  • In the tSQLt post-script as the last statement write "EXEC tSQLt.RunAll"
  • Create publish script in tSQLt project and in the settings be sure that it will deploy "extended properties"
  • Make sure that all test classes (schemas) have extended properties statements

There might some other nuances but just start with something and I am pretty sure that you'll start loving tSQLt very soon.

Actuary answered 19/12, 2017 at 8:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.