Project Greenfield: Testing the TDD Waters
NOTE: if you are just here for the video, the link is here: http://www.developingfor.net/videos/TDD1Video/
I’ve mentioned recently in Developer Growth Spurts and Project Greenfield that I am trying my hand at Test Driven Development (TDD). I’ve been reading a lot about it and have given it a go on a couple of occasions. I’ve been sidelined the last week or so by a billable project with a deadline (I supposed paying the bills is kind of important), so I’m not focused on Project Greenfield right now, but I don’t see that as an excuse to completely halt my progress.
Taking Advantage of the Unexpected
The good news is that the side project fits very well into the overall goals of Project Greenfield. The project is a pretty straightforward conversion project, reading data from our legacy database and writing it to a SQL Server database. I even get to design the schema of the target database.
I suppose a SQL Server guru would use SSIS or something like that to accomplish this task with no code, but that is well beyond my SQL Server skills at the moment. The project does, however, give me the chance to experiment with a few other technologies that I will be using in Project Greenfield, so I am trying some new things out and only billing half-time to make up for it with my client.
This is my first real project using SQL Server, small though it may be. I’ve messed around with it in the past, creating some tables and relationships for a co-worker, but this is something that will actually be going into the field so it is different. The first thing I did was build the schema based on the client’s specifications. As I was doing so, I realized it was wrong, but I finished it anyway because I didn’t want to stop progress to wait on a response. Once I was able to communicate with them, they agreed with my concerns and now I am fixing the problems, which are largely normalization issues.
I will share though, that I think I screwed up. My first instinct was to use a SQL Server project in Visual Studio, largely so it would be under version control. Unfortunately, when using such a project failed to be intuitive, I quickly gave up and went with what I know. In Visual Studio I connected to my local SQL Server Express, created a Database Diagram, and used it to create my schema.
This works just fine, except I now have no way to get to that database to extract the schema for my client. I know the answer is supposed to be to use SQL Server Management Studio, which I have installed for SQL Server 2005, but I need one that works with SQL Server 2008 Express. I found it online and downloaded it, but it won’t install. I’ll have to spend some time soon fixing this or come up with another solution. I do have a couple of ideas that would involve using …
Entity Framework 4
The next thing I am doing differently is using Entity Framework 4 for all of the SQL Server database access. Don’t get me wrong, I’m not doing anything really complex: all I need to do is connect to the database and write new records in a handful of files. But it has given me the opportunity to understand how to work with the Entity Context, how to manage object creation, experiment with how often to write records, learn about object relationships, and more. I feel much more confident with EF now.
This was helped by spending some time this weekend at Richmond Code Camp with Dane Morgridge. I was able to sit in his EF4 presentation and we spent some time coding together later, so I learned a bunch more about EF in the process. But he gave me some great guidance, and as it gels more I’m sure I will write about it. We also talked about Dependency Injection and some other stuff: folks, THIS is why I love community events so much!
Test Driven Development
If you’ve managed to read this far you are surely asking yourself “I thought this was supposed to be about TDD?” Fair enough, I just wanted to lay some of the ground work for the project.
I started this project with the intent of implementing TDD. I felt that a small project like this would be ideal to get my feet wet, and I will say so far so good. I’m sure I’m not doing it “just right”, but I am doing it which is a huge step forward. A buddy of mine said this weekend that just trying TDD puts me far ahead of most .NET developers when it comes to testing. I’ll take that with a grain of salt, but in a way I’m sure he’s correct.
As usual, I really started with the best of intentions. I began with an empty solution and created two projects: the working project and the testing project. I began writing code in my Test class first, then allowed the magic of ReSharper to help me create the classes and methods I was testing. I also used the NUnit Code Snippets I wrote to speed production.
I quickly ran into my first need for a mock object. I have a huge pre-existing DAL project that handles all of the legacy database work. The main class I would be using is about 3500 lines of codes, so naturally I wasn’t about to reinvent the wheel. I also thought at first that mocking this class up would be inordinately difficult, but I was willing to go down the rabbit hole for a little while to see where it led.
Where I ended up, at least at first, was actually not that bad. I used ReSharper once again to extract an interface from this huge class. At first, I thought I found a ReSharper bug: my entire computer froze for about 4 minutes. The mouse disappeared, the keyboard would not respond, windows would not focus, etc. I was basically locked out of my machine. I let it sit for a while and sure enough it came back and the new Interface file was created.
Now for my mock object: I created a test class in my test project that implemented the same interface. I did make one mistake: I allowed the implementation to throw Not Implemented exceptions. This caused some issues later, so I changed it to just create default auto properties.
Now for one of the beauties of TDD: because I was committed to writing the tests first and then writing just enough code to make it pass, I did NOT try to implement all the properties and methods of my test class. Instead, I implemented each one as I was testing it! This helped with the mocking a lot since there were plenty of properties and methods I was not using in this project.
And Not Mocking
This worked great for a while, but I admit that it eventually began breaking down. Or rather, I began breaking down.
I ran into what I considered a practicality issue. It may fly in the face of TDD, Unit Testing, and Code Coverage, but I got the feeling that there are just some things I don’t need to test. The legacy database DAL has been used extensively: I know it reads data from the database correctly, so I’m not goi
ng to try to fit in a bunch of tests after the fact. If I was starting from scratch perhaps I would, but at this point in the game there just isn’t enough ROI.
I came to the same conclusion with Entity Framework: I’m pretty sure that I don’t need to test that putting a string into a string variable in an EF class actually works. And for about 90% of this project, that’s all I’m doing: moving strings from the legacy database DAL to my new Entity Framework classes. So I decided that when that’s all I’m doing, moving one piece of data from old to new, with no reformatting, type conversions, or anything like that, then I was not going to write tests for those operations.
So the tests I did write for that first class were only for times when I had to convert or reformat the data. This was good because it severely limited the number of test scenario I needed to cover. I expect this is an issue I will have to figure out at some point: I know the goal is to test everything, but surely there must be a line drawn somewhere.
And then I ran into an issue where Mocking didn’t seem feasible. And before I go any further, I recognize that I am not talking about mocking frameworks or auto mocking or anything like that: I guess what I am really doing is called stubbing.
As I got further into the conversion, I began to rely on data from the legacy database. I could have faked all these classes, but it would have taken a lot of time and effort for very little reward. Fortunately, and one of the reasons it became difficult to mock all of this out, is that much of the data I needed at this point is static system data. Faking this stuff out would have just been a nightmare, so instead I chose to integrate a single database connection into my unit tests.
I realize this breaks a few rules. It means I have to be connected to my network at my office to run these particular tests. It means that my tests, and ultimately my code, is brittle because if this dependency. Which means that I should probably be using a mocking framework and Dependency Injection to solve some of these problems. Not to worry, I’ll get there!
I’m sure the TDD and testing purists would have a field day with my decision. And I’m cool with all of that, I welcome the comments.
Houston, we have Video!
During these adventures I thought it would be interesting if I shared some of the Project Greenfield content as videos. As a result, I am happy to announce the first ever Developing For .NET Video, available for viewing at http://www.developingfor.net/videos/TDD1Video/
Rather than walk through some Hello World/Calculator TDD example, this video contains, among other things, a walk through of a real world TDD sample. I have a method I need to create, so I write a Unit Test first, use it to create the Method, write enough code to compile but fail, then write enough code to pass, all in a real production project!
I would love to hear your comments about the video, so please add them to this post.