Charlie Calvert presented a preconference tutorial on Test Driven Development.
You can get to the presentation, code and notes by visiting www.elvenware.com. This is a subset of the information available there along with some of my impressions and interpretations.
Unit Testing is not tied to any methodology, but it works well with a number of agile methodologies. Related technologies include Patterns, UML and especially Refactoring. In fact you shouldn't refactor unless your code is well covered by unit tests.
A side effect of complete unit tests is they provide a specification and documentation for the project. If the tests are all created first then they provide the specification and measurement of progress on the project. When the tests pass then the requirements are complete, and the tests document the routines. Programmers would rather write and read code instead of specifications and documentation, so if a unit test, being code, provides documentation and specifications then the programmers are more likely to create documentation and use specifications. If the tests pass, and they are well designed, then they provide current documentation.
During the development process unit tests provide rapid feedback since you can run your tests early and often. This can let you know if your changes break another part of the program. It can also provide feedback to the users.
Creating the test first - that exercises only what is needed - and then a stub for the method (resulting in a test failure), then only adding the
- Create the tests first
- Only tests the required features of the method
- One test per method is the preferred way
- There may be multiple checks on the results after the one test per method
- Create an empty stub for the method
- Run the tests and it fails the new ones
- Add only the code necessary to meet the requirements of the test
- Run the tests again
- If it fails then correct the method and rerun the tests
- If it passes then continue - don't add other unexercised and unrequired features
- Refactor
- Re-test
Reasons not to Use Unit Tests
Assuming you already have reasons to use it. Don't read these reasons unless you already have reasons to use unit tests. Don't let these reasons talk you out of if completely, but just so you have your eyes wide open before going in, and also are willing do what it takes.
- It requires a lot of work as you write one or more test per method, class and procedure in your project. You should be prepared for the upfront time commitment and realize that they payoff will come later.
- It will radically change the way you write code and the way you do your projects. Testing through-out development instead of at the end.
- May cause a conflict with managers and co-workers if they don't understand the reasoning behind using unit tests.
- Unit tests should be easy, flexible and simple, and at first you may not yet know how to do them correctly.
- They are not a silver bullet. If the code is really bad, or the project is very poorly designed then unit tests will not necessarily fix it.
Unit Testing
Setup and Teardown is run before and after each test method. Tests should be discrete and independent so the order of the tests doesn't matter.
Tests should be named Test* or otherwise meet a specific syntax as expected by the framework.
Automate your tests to run as a console application, then grep the results for failures. Or some other automation where you will be notified of a failure. Tests should run during the night and multiple times during the day.
Philosophy
Four variables
Let your users / management pick 3 items. The 4th one is the flexible and the developers set the level on.
XP
Unit testing is required for the other features of XP. Everything should be tested. You will write the test first, then the code. The tests should run multiple times per day.
Refactoring is the process of improving existing code. Refactor code to make it simpler and more flexible and reduce the costs of change. You need unit tests before you refactor. Refactoring is about improving design without adding new features.
Keep code as simple as possible. Never write more code than the minimum you need to make it work. Start out with the assumption there is a simple solution. If it is complex then break it into smaller pieces.
90% is easy and 10% is hard. Try leaving this difficult part out based on the concept that it will result in a more stable program in much less time for less money. If there is a choice between coding for a contingency now and doing the minimum then just do the minimum now.
With unit testing and refactoring then dealing with these possible future issues (the last, expensive 10%) can be done in the future at a much lower cost. You may never need that last 10% so you have saved the time and money. If you do need to add it later then you only pay the cost when you need it. Expect change and know that it will come, so you really cannot plan ahead (adding features for the future). Do it simply today and keep it so you can easily change it tomorrow. Make little tiny changes, iterative development, release often
Code that is easy to test is easy to use. It should be encapsulated and uncoupled.