Print Article
Add to your CodeProject bookmarks
Comment on this article
Report this article as inappropriate
On structuring your testsOn structuring your tests
A Technical Blog article.
View entire blog here.
CodeProject
The ideas presented here are nothing new; however, a recent discussion with Dror Helper made me want to state my views on this subject (and make the whole world agree with me, whatever it takes), because to be honest, despite my best efforts in meditation, when I see a class called " The idea is, if you do TDD, you don't start with a class, because if you do, you already have some design before you have written any tests. So, you start with a user story. Ant let it be a Web app, to be more concrete. Here it goes: When a user fills the registration form correctly and hits the "Register" button, several things happen:
Now, if I were to start writing unit tests for a particular class, which class would it be? The specs say nothing about classes or such. So, first, I decide that it's going to be an MVC app, like all the cool guys doing these days. And I'm going to start with the most exciting thing: my controller. So, I'm creating a class called
So you end up with either one test with three asserts (which is a bad practice), or three test methods related to one particular feature. What makes it a mess is that you're going to add more tests: related to input validation, and to the other features that are handled by this controller: password change and retrieval, email confirmation, etc. For every action method, you can have 5-10 tests. On the other hand, the actual confirmation email sending belongs to a different class, so you probably put the test there, together with other email-related tests. You see, one big problem is that each test class becomes huge. But what's more important, it is hard to tell what your system does. One purpose of tests is documentation, and it should be readable for outsiders. If I am to figure out the behavior of the system in the registration process, where should I look? How do I know that part of it is in the And still another problem is that you just wrote a lot of code, but made zero business value with it. I mean, I can't register at your site yet! And won't be able until you write all the pieces and connect them together (for which you probably should write an integration test). To summarize, what you get with this approach is:
There's a Better WayNow, let's do it another way. Let's create a folder called Membership, and inside it a folder called "Registration". We're testing the case when we submit valid registration data, so let's make a test class called " WhenSubmittedValidRegistrationData.ShouldSendConfirmationEmail -- passed.
This is quite close to documenting your system! Now, you can still write it as a unit test for your controller, if you prefer, but I suggest you start with integration tests. I use Ivonna for testing, and it makes it a lot easier: my "integration" is only server-side. In addition, I can use several built-in CThru aspects, like EmailSpy, and I can use a lightweight in-memory database. I initialize the posted values (Arrange) and execute the request (Act) in the
Now I can go the full Red-Green-Refactor way. I stuff all the code into my action method until all my tests pass. At this moment, my system actually works: I can register a user! But my code is ugly: it is a quick-and-dirty solution written just in order to make my tests pass. I want to make it better. So I refactor it. It's at the refactoring phase that unit tests can provide a big value. Yes we all know that unit testing can lead us to a much better design. But sometimes it is enough to do it mentally. For example, "how would I unit test my controller"? Oh yes, I should refactor the email-related code into a separate class, and do dependency injection. Probably extract an interface like There is another situation when we have a particular feature that produces some output depending on various inputs, and it's not a yes/no situation, like in the previous case. Take searching, for example. You start with an integration test, like before. And make it work. For one of several search form parameters, you know that the search produces the correct results that appear in a grid on the search results page. It would be wasteful to write integration test for every search parameter. So, assume we already have it refactored into several units (note that I don't say "classes"): Here's the Recipe for Happiness
LicenseThis article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) About the Author
Comments and Discussions
| |||||||||||||||||||||||||||||||