Impact of Test Driven Development together with test automation on the software design.
I have already mentioned test driven development (TDD) in previous post on this blog. This is often also referred to as test first development.I am TDD practitioner myself, and recommend it highly. Although, some of the other XP techniques can be strongly debatable, I believe that TDD development and continues integrations are mandatory methodologies for the success of a software project today. From being the poor cousin of development, the unit testing - has become welcomed as the heart of the software development.
- It is the best way of achieving comprehensive test coverage. Retrofitting test to existing code doesn’t produce quality test and it is not exciting at all for developers.
- Writing test along with the application code can helps to define the requirements on each class. Theirs is nothing like writing a test first to make think about requirements of a method. What should it do on null argument? Should it return null or throw an exception.
- Having comprehensive test suite gives us effective regression testing. We can add new functionality and even more importantly, have the courage to refactor existing code (an essential ability in order to have clean and maintainable code base).
- It helps you write the simplest possible code. We don’t need to write complex code until we have a test that proves it’s required. If we continue, we can’t have a test that proves it until we have clear business need for that reflected in the story card requirements. In my opinion, this has the most beneficial reflection over designing clearer, readable and more maintainable code.
- TDD means that developers have constant feedback about progress in the form of more and more passing test demonstrating required functionality. This is very satisfying.
- In my opinion, using TDD is much more fun and fulfilling.
It is not the most intuitive thing to test something that doesn’t exist. In order to become comfortable with TDD you should start practicing with full believe and fully apply this methodology. Very soon, the benefit would be very obvious. It is simple concept, but I need some working example in order to fully realize the power of TDD approach.
I will briefly summarize the most important steps in TDD development and demonstrate a very simple example.
The most important characteristic in TDD are:
- Test against interface methods, which could be generated using IDE support.
- Using interfaces is one the best Object Oriented principal and lead to very good overall design. Furthermore, testing against interfaces allows us to use mock object in our unit testing. Using mock objects can improve our unit testing and improve the performance of the test suite. It is very important that the tests run comparably fast because one of their purposes is to give constant and fast feedback to developers. Another advantage of using mock objects is that your test is more accurate and allows truly unit testing.
- Always, always make the test to fail first. This is very important and often forgotten in practice. My experience has shown me that many times tests pass even if they are wrong. You should make sure that a test fails first in order to be sure everything is alright when the next time the same test pass.
- Write negative test first. This is a test that verifies behavior beside the normal path of execution. Example of that could be data access exception during DAO testing or what happens if a required parameters has not been initialized. Such scenarios are hard to reproduce in a deployment environment, and hence hard to cover in component and integration testing.
Before a demonstration of TDD with a simple test case, I want to mention here that in order for TDD to have the desired effect, developers should create pure unit test. The most popular and sufficient Java framework is JUnit. The design and the decision for technologies that will be used should be strongly impact by the fact whether it is easily testable and in some cases, if it is testable at all. I want to add immediately here that no test can prove full coverage and suffice by itself for good testing approach to a particular application. A TDD development implies that developers are mainly involved in unit testing, also known as white testing. Continues integration testing and rigorous functional testing are invaluable testing approaches but they should not be primarily responsibility of developers.
As a practitioner of TDD I wouldn’t choice working with EJB technology if I have other valuable alternatives. EJB are managed during runtime by EJB container. Its development is not only very complex but it very hard, and in some cases (Entity Beans) it is almost impossible to test, not to mention that TDD is unthinkable. Attempts are made to solve this problem with EJB mocks, which is not very successful and using in container testing frameworks as Cactus. Although, using Cactus is irreplaceable for integration in container testing of EJB, it can not be used for pure unit testing. As I mentioned before, unit testing should provide very fast feedback to a developer in order to be useful. Using cactus as unit testing implies that for testing of even single method, we should wait for deployment and very complex initializing operations of the targeted container before we have a feedback. Not to mention the complexity of setting up Cactus framework on the firs place.
TDD demonstration:
Requirements:
Business functionality: Withdrawal
Can anticipate: - Refusing access to data storage
- Insufficient Funds in the account
Prerequisites: - There is an existing account (I am really hoping for. J.)
- The account can accept deposits.
- The account knows the current balance.
Targeted test code:
public class BankAccountTest extends TestCase {
private BankAccount account;
protected void setUp() throws Exception {
account = new BankAccount();
}
public void testValidWithdrawalSuccedsWithinLimit() throws DataAccessException,
InsuffiecientFundsException {
account.setBalance(45.0);
account.withdrawal(20.0);
assertEquals(25.0, account.getBalance());
}
public void testNotValidWithdrawalFailOutsideLimit() throws DataAccessException{
try {
account.setBalance(45.0);
account.withdrawal(46.0);
fail("Bank should have rethrown InsufficientFundsExcepiton");
}catch(InsuffiecientFundsException ex) {
assertEquals("Correctly calcualted amount fo unapproved overdraft",1.0, ex.getShorfail());
}
}
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.