THANK YOU, SPONSORS! Rockstar Sponsors!
THANK YOU, SPONSORS! Gold Sponsors After Party Sponsor Breakfast Sponsor
THANK YOU, SPONSORS! Silver Sponsors Bronze Sponsors
How to Make Friends and Influence Databases Unit Testing: How to Stop Worrying and Start Living
Intro Adam Hafner Senior Database Engineer at Payrailz Co-Leader of (605) SQL User Group 2004 DSU Alumnus IEEE Member, Friend of Red Gate Member/Contributor 21 years in technology, 13 years specializing in data adam.hafner@gmail.com @ahafne01 https://www.linkedin.com/in/adam-hafner-b309213/
Scope What this is: An introduction into the concepts and principles of unit testing What this isn’t An in depth discussion of different testing processes (TDD, BDD, etc)
Unit Testing Definition: The boring slide Unit Testing Definition: “A software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use.”
Plain English Does your code do what you said it would? Everytime? Really…...are you sure? Are you really sure?? Ok, prove it… This sounds like a simplistic interpretation, but that’s all we are doing here. We are trying to verify that if I wrote a stored procedure that returns a person’s age based on their birthday, that it does just that. At face value that can seem pretty easy, but let’s not get ahead of ourselves too far yet.
But what about…. How about after Dave modifies it when you go on vacation for a week?
Key Principles of Unit Testing F-I-R-S-T
Key Principles of Unit Testing Fast Development can’t be slowed down by tests The longer a test takes to run the less time you have to write new code and the less time you have to fix issues with what was written
Key Principles of Unit Testing Isolation Imagine a deserted data island The data only belongs to the test No people interact with the data during the test
Key Principles of Unit Testing Repeatable Tests need to be able to be executed multiple times without intervention, setup, or pre- requisites
Key Principles of Unit Testing Self-Checking Tests need to result in a single, binary result There is no “sorta-pass” Focused on deterministic results
Key Principles of Unit Testing Timely Tests can not take a disproportionately long time to write compared to the code being tested
Key Principles of Unit Testing Unit testing is not to be confused with performance testing or integration testing Unit Tests verify Functional Requirements Performance Tests verify Non-Functional Requirements Integration Tests verify how different methods work with each other A test may verify that certain value is returned to support integration with other features, but it doesn’t test the actual integration with the other features
Most Difficult Principle: Isolation You might be violating the Isolation principle if: You utilize data that is not created during the execution of a test You rely on the results of a function that is not the target of the test you are writing You rely on the results of a stored procedure that is not the target of the test you are writing You are testing multiple result conditions in a single test Your test involves more tables than are actually referenced by the object being tested
Impact When we write tests we can’t use production scale data, large of amounts of data slow down tests (Fast) That’s good, that means I don’t have to wait for data to start writing code! When we write tests we can’t base our tests on other development items (Isolated) That’s good, that means I don’t have to wait for Dave to finish his code before I can start writing my code! When we write tests we can’t make our tests rely on the existence of data provided by users or other developers (Repeatable) I don’t have to wait for other people to make data for me, seems like a plus
Impact (Con’t) When we write tests our tests can’t generate results that are left up to individual interpretation. (Self-Checking) Oh, now I don’t have to be concerned about grey areas, just facts When we write tests we can’t involve data or be concerned with testing other development items that doesn’t pertain to the specific test (Timely) Now I don’t have to write massive tests or retest things that other developers already tested
But How!? Frameworks (tSQLt, DBUnit, DBTD, SSDT, many others) Frameworks impose language requirements (T-SQL, C#, Java, Proprietary, etc) Add features for other outside objectives (CI/CD, DevOps, Code Coverage, etc) Common Features Fake/Mock/Stub functionality Assertions Test Suites
Fake/Mock/Stub Differing interpretations Used to provide various degrees of isolation Really wide tables that holds a lot of unnecessary data - Fake It! Required fields values that aren’t being tested - Fake It! Ancillary function used by a tested procedure - Fake It! Foreign keys on a table that doesn’t impact the tested procedure - Fake It!
Assertions Evaluate a test condition and return binary results Used to support Self-Checking and Timely principles of unit testing
Test Suites Groups tests for similar features together Allows for automated execution of the group to quickly demonstrate that all tests passed or failed Allow for sharing of related test data or setup routines needed for all tests of the same type
Now That You’ve Selected a Framework... How do you know what to test?! If it was worth coding, why wouldn’t it be worth testing? ...but the code is too complex Refactor ...but the test is too complex ...but I don’t know how to test it That’s ok! It’s a learning process! At one point you didn’t know SQL either! ..but I don’t know what to test That’s ok, see next slides...
What Tests Are Necessary Test Case Heuristics Acceptance Criteria If they exist, usually it’s the tip of the iceberg 3 Popular Approaches to Test Development (Sebastian Shoutout) Boundary Conditions Special Values 0-1-Some
Boundary Conditions Boundary: Any input value that causes a change in behavior Always look left then right Scenario - Sliding Scale Pricing (If I buy 1-5 widgets the price is $10/widget, if I buy 6 or more widgets the price is $9/widget) Example Test Cases: 1 widget, 2 widgets, 5 widgets, 6 widgets, 9 widgets
Special Values Uncommon, unexpected, or “interesting” values that could cause varying results Y2K, anyone? Example Test Cases: NULL quantity, negative quantity, very large quantity, 0 quantity
0-1-Some Testing behavior of code that interacts with sets How does your code react to varying number of results? Example Test Cases: If a single order has multiple line items of widgets with varying quantities? No lines? A single line?
5.2 Average number of bugs per development item *
89.3 Percent of developers state that they have verified that their code “works as designed” *
Number of development projects that are performed by a single person and will never be touched by anyone other than that person * * Statistics made up for the purpose of this presentation :)
What do you do about it? “Be the change you want to see in the world.” - Ghandi “The journey of a thousand miles begins with one step” - Tzu “You miss 100% of the shots you don’t take” - Gretsky “Just do it” - Nike <Insert Motivational Quote Here>
If you liked this presentation, look for the upcoming presentation on implementing unit tests in SQL using tSQLt
Resources/Citations https://sqlity.net/en/blog/ http://blog.dgta.co.uk/search/label/tSQLt https://www.itprotoday.com/sql-server/getting-started-test-driven-design-sql-server https://www.sqlservercentral.com/articles/an-introduction-to-test-driven-development https://tsqlt.org/ http://sqlunit.sourceforge.net/ http://dbfit.github.io/dbfit/ https://sourceforge.net/projects/tsqlunit/ https://sourceforge.net/p/uttsql/wiki/ https://archive.codeplex.com/?p=tst https://github.com/vassilvk/slacker