Friday, October 23, 2009

Test First Design and Refactoring










Test First Design and Refactoring


Test-driven development (TDD) has brought the concept of test first design to the fore-front. This approach has several benefits and hence we will write tests first in this book, whenever possible.


Writing tests first takes a little bit of getting used to, and many times, you will wonder if you really have the time to write tests given the pressure of deliverables. However, I find it is a nicer way to code (after you get the hang of it), particularly because it helps me think of how to design/develop my classes. Also, if you factor in the time you spend unit testing and fixing defects discovered during functional and user testing, you will find that this style of working can actually save time in the end.


Writing tests first has several benefits. For example, writing tests first ensures that you write only functional code that will actually be used; this is based on the assumption that you have written code to satisfy the unit tests, which themselves are based on the acceptance tests specified earlier in our business requirements. Second, if your code passes the unit and acceptance tests, you are done with that part of the code. Third, it can help you design your classes better because when you write the test first, you are experiencing firsthand how your actual classes/methods will be used. Last, test first can also help you to refactor with confidence because you can retest your refactored code quickly through JUnit unit tests to ensure that the refactored code works as the original version did (assuming there is little or no change to the external interface, as defined on refactoring.com).


Although, unit testing is only one part of the overall testing that occurs in corporations, it is something that developers should always do. Other testing includes functional testing, user acceptance testing (UAT), system integration testing (also known as interface testing), stress/load testing, and more.


We will use JUnit to implement our acceptance tests. The following are sample files to demonstrate our class-naming convention for test classes:


  • test/TimesheetListControllerTest.java

  • test/TimesheetManagerTest.java

  • test/ReminderEmailTest.java


I have chosen to keep our JUnit test classes in a separate test package (that is, com.visualpatterns.timex.test) because I believe this is a cleaner design. However, I've also seen other developers keep the JUnit test classes in the same directory as the code being tested. For example, in this scenario, our TimesheetListControllerTest.java would be placed in our controller package.





Personal Opinion: Early Environment Setup Is Essential


After almost two decades of developing software, I am amazed how little some of the fundamental concepts have changed. Although the technologies have changed dramatically, underlying concepts such as environment setup, design, development, debugging, and so on remain fundamentally the same. One of things I have consistently found over the years is that the environment setup almost always involves more than people expect or plan for. So, getting the environment setup upfront is vital. Based on my personal experience, I like to recommend three things to my customers in regards to environment setup.


First, get the minimal but completely functional environment set up up front (directory structure and build scripts, for example). This should be consistent for all members of a software development team. Second, get a simple end-to-end demo working up front (for example, a user interface to database round-trip demo). Third, environment setup generally takes longer than people expect, so factor in enough time up front. This is one reason many Agile projects consider this iteration 0 (zero) or cycle 0 (Jim Highsmith), because a demo or environment setup doesn't produce anything tangible from a customer perspective; it merely gets the environment setup for developers and testers to work in.














No comments: