56
Test-Driven Database Development with DataDude Cory Foy http://coryfoy.com | @cory_foy

Test Driven Database Development With Data Dude

Embed Size (px)

DESCRIPTION

In this presentation, we go through the features of Visual Studio Team System Database Edition showing how you can use the refactoring, testing and data generation tools to to Test-Driven Development in SQL Server.

Citation preview

Page 1: Test Driven Database Development With Data Dude

Test-Driven Database Development with DataDude

Cory Foyhttp://coryfoy.com | @cory_foy

Page 2: Test Driven Database Development With Data Dude

Agenda

Overview Features Demos Availability Other Tools

Page 3: Test Driven Database Development With Data Dude

Agenda

Overview Features Demos Availability Other Tools

Page 4: Test Driven Database Development With Data Dude

Overview – TDD

TDD == Test-Driven Development Developer Design Technique Red-Green-Refactor

Write a failing test Write just enough code to make it pass Refactor any duplication

Page 5: Test Driven Database Development With Data Dude

Overview – TDD in DBs

Why is agility at the database so hard? Control / Permission issues Tightly coupled applications No good testing tools Data Migration issues

If it hurts, do it more

Page 6: Test Driven Database Development With Data Dude

Overview – Agile Defined

Agile Manifesto Individuals and Interactions over

Processes and Tools Working Software over Comprehensive

Documentation Responding to Change over Following a

Plan Customer Collaboration over Contract

Negotiation

Page 7: Test Driven Database Development With Data Dude

Overview – Agile Defined

Agile Manifesto Don’t rely on tools and processes to save

you Talk to your data experts, your

developers Find common ground Make incremental improvements Build a safety net

Page 8: Test Driven Database Development With Data Dude

Overview – Goals of DataDude

Integrated Change Management for DB Apps

Provide Tools to Manage DB Projects Assess effects of changes to the DB Help work in an isolated environment Help test Updated Solutions Simplify the deployment of changes Facilitate Collaborative Development

Page 9: Test Driven Database Development With Data Dude

Overview - Editions

DataDude (2005) (Add on to VSTS) Team Edition for Database

Professionals (2008) Visual Studio Team System Database

Edition (2010) Comes for free with VSTS Developer

Edition

Page 10: Test Driven Database Development With Data Dude

Overview - Tasks

Create and Deploy DBs under version control

Put existing DBs under version control

Modify Offline Representations and deploy

Compare Schemas and Data between DBs

Develop and run unit tests against DB Objects

Generate repeatable test data Refactor database changes across

the DB

Page 11: Test Driven Database Development With Data Dude

Agenda

OverviewFeatures Demos Availability Other Tools

Page 12: Test Driven Database Development With Data Dude

Features

Version Control Database VC a new or existing database Refactor Compare DBs Generate Deployment Script

Unit Test Database TDD Schema Changes TDD Business Logic Change Generate Test Data

Page 13: Test Driven Database Development With Data Dude

Agenda

Overview FeaturesDemos Availability Other Tools

Page 14: Test Driven Database Development With Data Dude

Demo – Version Control Database

Cory Foyhttp://coryfoy.com | @cory_foy

Page 15: Test Driven Database Development With Data Dude

Version Control Database

Existing Schema

Two Tables - Msgs, Users

Two Stored Procs - PostMsg: Posts a message for a specific user to the database. Take a UserID and varchar message as a parameter - UserInfo: Takes a UserID and returns back all of the user information, including how many posts they’ve made

Page 16: Test Driven Database Development With Data Dude

Version Control Database

Get Database Under Version Control

Page 17: Test Driven Database Development With Data Dude

Version Control Database

You now have an isolated copy you can work with that doesn’t change the source database

Page 18: Test Driven Database Development With Data Dude

Version Control Database

We want to change “Msg” to “Neet” everywhere it exists in the database.

This will require a change to the Msg column in the Msgs table, renaming the Msgs table itself, and updating the Stored Procs.

We could do it by hand, or we could use the refactoring tools built in.

Page 19: Test Driven Database Development With Data Dude

Version Control Database

We use the Refactoring Option to rename the column, and by selecting “Preview Changes” it shows us what it is going to do

Page 20: Test Driven Database Development With Data Dude

Version Control Database

We can even see the change in the context of the DDL by clicking on the change in the preview window.

When we click on Apply, the change is made to the version controlled local copy.

Page 21: Test Driven Database Development With Data Dude

Version Control Database

We also need to change the table name, so we can use refactor for that as well.

It detects the need to update the constraints as well

Page 22: Test Driven Database Development With Data Dude

Version Control Database

Changing the Stored Proc name can also be done through Refactoring

But changes to the values returned from the UserInfo stored proc would have to be done by hand.

Also note that the refactorings only look at the database – not your code which accesses or uses the database

Page 23: Test Driven Database Development With Data Dude

Version Control Database

We can now compare the schema changes to see how this would deploy it to the database

Page 24: Test Driven Database Development With Data Dude

Version Control Database

By Default, choosing to deploy creates a script which can be run to do the actual deploy

Page 25: Test Driven Database Development With Data Dude

Version Control Database

We can also choose to have it automatically deploy to a database. For example, here we have it deploying to a local SQLEXPRESS Database

And everything should still work (meaning no data loss)

Page 26: Test Driven Database Development With Data Dude

Demo – Unit Test Database

Cory Foyhttp://coryfoy.com | @cory_foy

Page 27: Test Driven Database Development With Data Dude

Unit Test Database

We have a new requirement for scalability. Instead of doing a count for user_info, we want a new table which just has a user_id and count. This field should be updated on every Neet by the user, and should be the one queried to get the current Neet count.

But, we want to make sure that all of our existing scripts work. Unit Testing to the rescue!

Add a new Test Project to our Solution, then delete the UnitTest1.cs file. Then right-click on the Test Project, do a New->Add Item, and select Data -> Database Unit Test. Name it NewNeetUpdatesNeetCount

Page 28: Test Driven Database Development With Data Dude

Unit Test Database

Database Unit Tests execute against a real database connection. So we’ll need to tell it which database to execute against.

Note that in this screen we can Execute the tests using one connection, and validate using a different one. This is important when you have your production code which uses a limited access user.

We’ll also have it automatically deploy the project to the database before the tests are run

Page 29: Test Driven Database Development With Data Dude

Unit Test Database

We now see the DB Test screen. Note that we can have Pre-test, Test and Post-test scripts. These can be used for setting the database into specific states. All tests are written in SQL, and then validated by the Test Conditions at the bottom of the screen.

Page 30: Test Driven Database Development With Data Dude

Unit Test Database

What we’re wanting to test is that, with an existing user who as Neet’d before, when we call the PostNeet stored procedure, that the NeetCount table is updated. So our test will look something like this (Arrange, Act, Assert)

We’ll then need to remove the default test condition (by clicking the Red x)

Then we’ll choose “Scalar Value” from the drop down and hit the plus sign, configuring it to expect that the last query our test runs will return the value “1” in Row 1, Column 1

Page 31: Test Driven Database Development With Data Dude

Unit Test Database

Next, we’ll run the test using the built-in runner. Note that the first time you run the tests, it will be slow because it has to synchronize some information.

You’ll see the test failed, and if you right-click on the test and say “View Test Result Details” you can see the exact error message

The error is that we don’t actually have a table called NeetCount. Well, this will never do, let’s add it.

Page 32: Test Driven Database Development With Data Dude

Unit Test Database

So, do we go to the database? Nope – we make the change right from our project. In our schema view, we click on the Tables node, then choose Add->Table.

We’ll name it NeetCount so we stand a chance of having our unit tests pass.

We’ll also fill out the DDL to have the columns we are looking for and save it.

Page 33: Test Driven Database Development With Data Dude

Unit Test Database

Now we’ll rerun our tests. And they fail again. But for a different reason this time

Yep. Our table is there, but nothing is being inserted. How did our table get there? Remember that when we setup the test we told it to deploy the DB project before running tests. So it added the table to the database before running the tests – just by us clicking Run.

Page 34: Test Driven Database Development With Data Dude

Unit Test Database

Now that our unit test is failing for logic reasons, we can make the change to the stored procedure. Again, we change it by opening it from the Schema view rather than changing the database directly. But look at the proc. We’ve found our first business decision – at what point should UserID records get inserted into NeetCount?

It’s decided that upon user creation a record will get inserted in, and that we’ll need a migration effort to move existing records. With those taken care of, we can focus back on modifying this Proc.

(Yes, we’re ignoring transactions, etc for now)

Page 35: Test Driven Database Development With Data Dude

Unit Test Database

After updating our test database with the migration of data, we can rerun our tests

And everything runs succesfully! Now we know that post a Neet updates the correct count. It’s now time to make sure that UserInfo is pulling the information from the right table

Page 36: Test Driven Database Development With Data Dude

Unit Test Database

We create another Database Unit Test called UserInfoGetsCountFromNeetCount. We’ll update the NeetCount for our test user, then execute the UserInfo and we should see the updated count. We’ll start with choosing the Pre-test option and filling it in, then setting the actual test up

And running our tests shows it fails for the “right” reason

Page 37: Test Driven Database Development With Data Dude

Unit Test Database

So now we’ll modify our UserInfo stored proc to make the test pass.

And it does!

Page 38: Test Driven Database Development With Data Dude

Unit Test Database

While what we’ve done works, it is better to capture the logic of a change like this in a way that shows the business value and the coupling. Let’s create a new Database Unit Test and call it EnhanceUserInformationPerformance. We’ll add two tests in this for the two conditions we covered previously. Use the Rename button to rename the first test, then click the plus sign to add the second test. Copy over the logic for each from the previous tests, making sure to include the Test Conditions and PreTests

Page 39: Test Driven Database Development With Data Dude

Unit Test Database

Now let’s make sure they run. Go to Test->Run All Tests in Solution and they should all pass.

Now, let’s delete the first two tests we created in favor of this new combined test, and rerun all of our tests to make sure.

All well and good so far. But we should write one more test which does everything end-to-end

Page 40: Test Driven Database Development With Data Dude

Unit Test Database

Add a new Database Unit Test and call it NewNeetUpdatesUserInfo. We’ll use a temp table to capture the results of the UserInfo to compare against our expected values. Note that you *can’t* do this in pre/post test since those run in different connections, therefore the variables can’t be shared. So run the tests and see it green.

Right?

Or not. So what happened? Remember our Unit Test which updated the NeetTable directly? It’s polluted our DB, which invalidates our results.

Page 41: Test Driven Database Development With Data Dude

Unit Test Database

To get around that, we need to either run things in transactions (which we have to do all in the Test Script) or back our changes out. In this case, we’ll just revert the changes at the end of the script in Post Test. So modify the UserInfoGetsCountFromNeetCount test and add the following to Post-test

Now go to Test->Run-> All Tests in Solution and what do we see?

That’s much better

Page 42: Test Driven Database Development With Data Dude

Unit Test Database

One thing to note about the Database tests – they are all just code and xml underneath. For example, right-clicking on one of our tests and saying “View Code” shows the “magic” happening underneath

These are just MSTest unit tests, so you can drop to the code level if there are special things you need to do with the tests.

Page 43: Test Driven Database Development With Data Dude

Demo – Generating Data

Cory Foyhttp://coryfoy.com | @cory_foy

Page 44: Test Driven Database Development With Data Dude

Generating Data

In our last demo, we saw the challenges data can cause us. We can use the data generation tool to help us populate the information in our database. Right-Click on the Knitter project in Solution Explorer and choose Add-> Data Generation Plan, then name it TestData.

If you click on dbo.Neets, you’ll see that UserID shows as a Foreign Key, but it doesn’t in dbo.NeetCount (because we didn’t add it). Fix that by Right-Clicking on the NeetCount table in Schema View and choosing Add->Foreign Key. Once you’ve filled it in, deploy it, then refresh the data plan

Page 45: Test Driven Database Development With Data Dude

Generating Data

NeetCount.totalNeets is effectively a computed field, but it’s not. So make sure the generator is Integer, and change the properties to be Max and Min of 1

We also only want our usernames (UserID in the Users table) to only be AlphaNumeric. So change the generator for that column to be Regular Expression, and in the Properties window, enter [a-zA-Z0-9]*_[a-zA-Z0-9]* then right-click on the UserID row and choose “Preview Data Generation”. As you can see, the characters run the gamut.

Page 46: Test Driven Database Development With Data Dude

Generating Data

With our test plan in place, we can have our unit tests use it automatically. Go to Test->Database Test Configuration and check the “Generate Test Data” box.

Now whenever the tests are run, the data is generated automatically.

Let’s rerun our tests to show the difference.

What a difference! They all fail because there is no UserID “1” in the database.

Page 47: Test Driven Database Development With Data Dude

Generating Data

To fix that, we’ll update the tests to select the top user from the users table, making sure we update all 3 tests, and the pre and post tests where necessary.

And that looks much better

Page 48: Test Driven Database Development With Data Dude

Generating Data

If we do an actual query in our test database, we’ll see that indeed the values get inserted there

The Database Edition comes with several generators – for each type, the Regular Expression generator, and Databound generators which can pull data from any connection – other databases, Excel files, CSV files, etc.

Page 49: Test Driven Database Development With Data Dude

Agenda

Overview Features DemosAvailability Other Tools

Page 50: Test Driven Database Development With Data Dude

Availability

Available in VS2005, VS2008 and VS2010

Requires a Team Edition of Visual Studio

Comes with the Team Edition for Software Developers

Page 51: Test Driven Database Development With Data Dude

Availability

Supports SQL 2000, 2005 and 2008 Plans are in place to provide data

bindings for other platforms but no timeline

Page 52: Test Driven Database Development With Data Dude

Agenda

Overview Features Demos AvailabilityOther Tools

Page 53: Test Driven Database Development With Data Dude

Other Tools

DBFit Supports Oracle, DB2, SQL Server and

MySQL Free of charge Add on to the FitNesse testing

framework http://www.fitnesse.info/dbfit:reference http://gojko.net/fitnesse/dbfit/

Page 54: Test Driven Database Development With Data Dude

Other Tools

AnyDbTest Supports Oracle, SQL Server and MySQL Uses XML as the backing http://www.anydbtest.com/

Page 55: Test Driven Database Development With Data Dude

Other Tools

Agile Data – Scott Ambler Agile Database Techniques Refactoring Databases http://www.agiledata.org

Page 56: Test Driven Database Development With Data Dude

More Information

http://msdn.microsoft.com/teamsystem

http://www.infoq.com/articles/tdd-dbpro-Foy

http://blog.coryfoy.com/2007/07/test-driving-stored-procedures-in-sql-server-in-vs2008/

http://www.coryfoy.com foyc at cory foy dot com @cory_foy on Twitter Slides will be posted on CoryFoy.com