Test Driven Development, or TDD, is the mainstream in many areas of software development, but what about the database? In this session, we explore TDD, the benefits of automated testing, and how testing data projects differs from other types of development. We introduce the tSQLt testing framework and demonstrate its use with a live coding example. Finally, we will discuss some lessons learned in doing TDD with SQL Server.
Originally presented by Steve Fibich and David Moore at Richmond SQL Server Users Group on January 11, 2018
2. About Us
Steve Fibich is a developer, problem solver,
and Architect for Markel Corporation. He
has been working with databases almost
20 years. He has a number of different
jobs in IT over his career: System Admin,
SQL DBA, Data Warehouse Designer, and
an Architect. He loves playing with and
learning new technologies. In his spare
time, he brews beer, goes to the gym and
spends times with his family.
David Moore is a software/data engineer
with 20+ years of experience in a variety of
roles, developing applications and data
solutions. With a passion for continuous
improvement, he seeks ways to make agile
practices practical. He serves as a senior
consultant with CapTech
3. What is Test Driven Development?
"Test-driven development" refers to a style of programming in which three
activities are tightly interwoven: coding, testing (in the form of writing unit
tests) and design (in the form of refactoring).
It can be succinctly described by the following set of rules:
– write a "single" unit test describing an aspect of the program
– run the test, which should fail because the program lacks that feature
– write "just enough" code, the simplest possible, to make the test pass
– "refactor" the code until it conforms to the simplicity criteria
– repeat, "accumulating" unit tests over time
Source: https://www.agilealliance.org/glossary/tdd
4. § Test Driven Development (or TDD originated in the late 90’s as part of Extreme
Programming, and were subsequently embraced by other Agile methodologies
such as Scrum.
A brief history of TDD
§ TDD has typically used an automated testing
framework such as Smalltalk’s sUnit, Java’s jUnit,
.Net’s nUnit, Python’s unittest, all following a
similar “xUnit” pattern
§ Testing methods such as Acceptance Test Driven
Development (ATDD) and Behavioral Driven
Development (BDD) have extended the ideas
introduced by TDD, using tools like Cucumber and
Gherkin
5. Improved Quality – Automated tests reduce number of defects
Increased Agility – Having existing automated tests allows teams to respond more quickly
to changing requirements
Reduces Risk - Having a suite of automated tests reduces risk when making changes to the
code and helps teams respond more quickly to change
Instills Confidence - Developers have confidence that they aren’t breaking anything when
changing existing code
Results in Cleaner Code – Having to design the code for testing results in
smaller/modular/loosely coupled components
Tests as Documentation– Tests can be used to help document what the code is
intended to do
Benefits of TDD
6. “legacy code is simply code without tests”
-Michael Feathers
“Code without tests is bad code. It doesn’t
matter how well written it is; it doesn’t matter
how pretty or object-oriented or well-
encapsulated it is. With tests, we can change
the behavior of our code quickly and verifiably.
Without them, we really don’t know if our code
is getting better or worse.”
7. ■ Test Suite – A collection of Test Cases
■ Test Case – Represents a single test
■ Test Runner – Framework used to run the tests
■ System Under Test (SUT) – The system that is being tested
■ Fixture – The environment and data needed for running the test
xUnit Framework components
Test Suite Test Case 1
Test Case 2
Test Case 3
Test
Runner
Runs
System
Under
Test
Tests
Fixture
8. 1. Setup – run any preconditions necessary for the test
2. Exercise – run the test
3. Verify – validate results (Pass/Fail)
4. Teardown – cleanup environment for next test
Each test typically has 4 phases
Reference: http://xunitpatterns.com/Four%20Phase%20Test.html
Test Suite Test Case 1
Test
Runner
Runs
System
Under
Test
FixtureSetup
Exercise
Verify
Teardown
9. tSQLt – The Database Unit Testing framework for
SQL Server
10. ■ Popular automated testing tool for SQL Server TSQL
■ Provides ability to write unit tests in TSQL and run them directly in SQL Server
■ Open source, licensed under the Apache 2.0
Source: https://github.com/tSQLt-org/tSQLt
■ Supports SQL 2005 and above
■ Broad SQL Server community support
■ Used by Redgate SQL Test, and dbForge Unit Test :
https://www.red-gate.com/products/sql-development/sql-test/
https://www.devart.com/dbforge/sql/unit-test/
■ Website at http://tsqlt.org
What is tSQLt?
11. ■ 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 – Supports standard Junit test output format
■ Provides the ability to fake tables and views, and to create stored procedure spies –
allowing you to isolate the code which you are testing
Main Features of tSQLt
12. Assertions are the main way that automated tests can verify whether or not the expected
conditions have occurred.
The tSQLt framework provides a number of assertion stored procedures:
tSQLt Assertions
§ AssertEmptyTable
§ AssertEquals
§ AssertEqualsString
§ AssertEqualsTable
§ AssertEqualsTableSchema
§ AssertLike
§ AssertNotEquals
§ AssertObjectDoesNotExist
§ AssertObjectExists
§ AssertResultSetsHaveSameMetaData
§ Fail
13. Expectations are used to test that an exception should occur, or should not occur
The tSQLt framework provides the following expectation stored procedures:
■ ExpectException
■ ExpectNoException
tSQLt Expectations
14. Sometimes in order to isolate the “unit” that is being tested, it is convenient to be able to
modify the code being tested using techniques such as creating fake objects or removing
objects.
The tSQLt framework provides a number of stored procedures that can be useful of
isolating dependencies:
■ ApplyConstraint
■ ApplyTrigger
■ FakeFunction
■ FakeTable
■ RemoveObject
■ RemoveObjectIfExists
■ SpyProcedure
tSQLt Isolating Dependencies
15. The following are the main controlling procedures used to run tests and organize tests into
groups of tests
■ Run – Run a single test
■ RunAll – Run all the tests in a particular test class
■ NewTestClass – Creates a new test class (schema) as a container for tests
■ DropClass – Deletes a test class
■ RenameClass – Renames a test class
tSQLt Test Control Procedures
17. 1. It looks at all the stored procedures in the test class (schema) that start with the word
“test”. These are all considered to be all the test cases for that test class.
2. For each of the test cases:
a) A record is created indicating that the test case is being executed in the
tSQLt.TestResult table.
b) tSQLt starts a transaction.
c) If there is a stored procedure named SetUp on the test class, it is executed.
d) The test case stored procedure is executed.
e) The transaction is rolled-back.
f) The record in tSQLt.TestResult is updated accordingly if the test case succeeded, failed
or threw an error.
3. The test results are displayed in the console.
What happens when tSQLt.Run is called?
18. ■ The tSQLt framework and tSQLt tests should not be run in production - only dev/test
■ Remember to prefix test procedures with “test”, otherwise the procedures will not be executed
by the tSQLt.Run procedure
■ A special stored procedure named “Setup” can be created in a test class schema, which will run
before each test is run. This can be used to set up the test fixture for shared fixtures that all
tests will use.
■ If you have to stop a test while it is running, make sure you execute a “rollback” command so
that the open transaction is rolled back
Other tips when using tSQLt
19. 1. Download and Install the tSQLt code in the database you want to test. Note: CLR must be
enabled
2. Run the procedure NewTestClass – providing the name of the test class as a parameter, this
creates a new schema for your tests
3. Create a test stored procedure in the test class schema, prefixed with the word “test”. The
stored procedure should do the setup, execution and verification, using the built-in assertion
procedures.
4. As the each test is executed in a transaction, there is normally no need to do an explicit
teardown.
Steps to get started with tSQLt
20. ■ Keep tests short – practice the “one thing” principle
■ Keep tests simple - no if/then branching – “how are you going to test the tests?”
■ Tests should not be dependent on other tests
■ Tests should be self-contained - not dependent on environment or external dependencies
■ Running of tests should be incorporated into an automated build/release process (i.e. with TFS,
Jenkins, etc)
Best Practices
21. ■ Tests need to be run often – daily or more frequently
■ Watch out for long running tests – they will lead to tests not being run
■ Having too many tests can also be a problem – balance number of tests with coverage
■ Test code is as important as production code – keep the test code clean
■ Tests need to be maintained
■ tSQLt doesn’t support certain types of testing out of the box. For example you can’t create a
database within a transaction. For this we needed to modify the standard behavior.
Lessons Learned
22. ■ Test Driven Development by Example – Kent Beck
– https://www.amazon.com/Test-Driven-Development-Kent-Beck
■ Introduction to Test Driven Development – Scott Ambler
– http://agiledata.org/essays/tdd.html
■ Test Driven Development – C2 Wiki
– http://wiki.c2.com/?TestDrivenDevelopment
■ xUnit Test Patterns – Gerard Meszaros
– http://xunitpatterns.com/ - Web site for book that catalogs xUnit Testing patterns
– https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code
■ Refactoring – Martin Fowler
– https://www.amazon.com/Refactoring-Improving-Design-Existing-Code
■ Clean Code – Robert C. Martin
– https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship
Resources