Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Test-Driven Java Development, Second Edition

You're reading from   Test-Driven Java Development, Second Edition Invoke TDD principles for end-to-end application development

Arrow left icon
Product type Paperback
Published in Mar 2018
Publisher Packt
ISBN-13 9781788836111
Length 324 pages
Edition 2nd Edition
Languages
Arrow right icon
Authors (2):
Arrow left icon
Alex Garcia Alex Garcia
Author Profile Icon Alex Garcia
Alex Garcia
Viktor Farcic Viktor Farcic
Author Profile Icon Viktor Farcic
Viktor Farcic
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Why Should I Care for Test-Driven Development? FREE CHAPTER 2. Tools, Frameworks, and Environments 3. Red-Green-Refactor – From Failure Through Success until Perfection 4. Unit Testing – Focusing on What You Do and Not on What Has Been Done 5. Design – If It's Not Testable, It's Not Designed Well 6. Mocking – Removing External Dependencies 7. TDD and Functional Programming – A Perfect Match 8. BDD – Working Together with the Whole Team 9. Refactoring Legacy Code – Making It Young Again 10. Feature Toggles – Deploying Partially Done Features to Production 11. Putting It All Together 12. Leverage TDD by Implementing Continuous Delivery 13. Other Books You May Enjoy

Why TDD?

You might be working in an agile or waterfall environment. Maybe you have well-defined procedures that were battle-tested through years of hard work, or maybe you just started your own start-up. No matter what the situation was, you likely faced at least one, if not more, of the following pains, problems, or causes for unsuccessful delivery:

  • Part of your team is kept out of the loop during the creation of requirements, specifications, or user stories
  • Most, if not all, of your tests are manual, or you don't have tests at all
  • Even though you have automated tests, they do not detect real problems
  • Automated tests are written and executed when it's too late for them to provide any real value to the project
  • There is always something more urgent than dedicating time to testing
  • Teams are split between testing, development, and functional analysis departments, and they are often out of sync
  • There is an inability to refactor the code because of the fear that something will be broken
  • The maintenance cost is too high
  • The time to market is too big
  • Clients do not feel that what was delivered is what they asked for
  • Documentation is never up-to-date
  • You're afraid to deploy to production because the result is unknown
  • You're often not able to deploy to production because regression tests take too long to run
  • The team is spending too much time trying to figure out what some method or a class does

TDD does not magically solve all of these problems. Instead, it puts us on the way towards the solution. There is no silver bullet, but if there is one development practice that can make a difference on so many levels, that practice is TDD.

TDD speeds up the time to market, enables easier refactoring, helps to create better design, and fosters looser coupling.

On top of the direct benefits, TDD is a prerequisite for many other practices (continuous delivery being one of them). Better design, well-written code, faster TTM, up-to-date documentation, and solid test coverage, are some of the results you will accomplish by applying TDD.

It's not an easy thing to master TDD. Even after learning all the theory and going through best practices and anti-patterns, the journey is only just beginning. TDD requires time and a lot of practice. It's a long trip that does not stop with this book. As a matter of fact, it never truly ends. There are always new ways to become more proficient and faster. However, even though the cost is high, the benefits are even higher. People who have spent enough time with TDD claim that there is no other way to develop a software. We are one of them and we're sure that you will be too.

We are strong believers that the best way to learn some coding technique is by coding. You won't be able to finish this book by reading it in a metro on the way to work. It's not a book that one can read in bed. You'll have to get your hands dirty and code.

In this chapter, we'll go through basics; starting from the next, you'll be learning by reading, writing, and running code. We'd like to say that by the time you're finished with this book, you'll be an experienced TDD programmer, but this is not true. By the end of this book, you'll be comfortable with TDD and you'll have a strong base in both theory and practice. The rest is up to you and the experience you'll be building by applying it in your day-to-day job.

Understanding TDD

At this time, you are probably saying to yourself, OK, I understand that TDD will give me some benefits, but what exactly is TDD? TDD is a simple procedure of writing tests before the actual implementation. It's an inversion of a traditional approach where testing is performed after the code is written.

Red-Green-Refactor

TDD is a process that relies on the repetition of a very short development cycle. It is based on the test-first concept of extreme programming (XP) that encourages simple design with a high-level of confidence. The procedure that drives this cycle is called Red-Green-Refactor.

The procedure itself is simple and it consists of a few steps that are repeated over and over again:

  1. Write a test
  2. Run all tests
  3. Write the implementation code
  4. Run all tests
  5. Refactor
  6. Run all tests

Since a test is written before the actual implementation, it is supposed to fail. If it doesn't, the test is wrong. It describes something that already exists or it was written incorrectly. Being in the green state while writing tests is a sign of a false positive. Tests like these should be removed or refactored.


While writing tests, we are in the red state. When the implementation of a test is finished, all tests should pass and then we will be in the green state.

If the last test failed, the implementation is wrong and should be corrected. Either the test we just finished is incorrect or the implementation of that test did not meet the specification we had set. If any but the last test failed, we broke something and changes should be reverted.

When this happens, the natural reaction is to spend as much time as needed to fix the code so that all tests are passing. However, this is wrong. If a fix is not done in a matter of minutes, the best thing to do is to revert the changes. After all, everything worked not long ago. An implementation that broke something is obviously wrong, so why not go back to where we started and think again about the correct way to implement the test? That way, we wasted minutes on a wrong implementation instead of wasting much more time to correct something that was not done right in the first place. Existing test coverage (excluding the implementation of the last test) should be sacred. We change the existing code through intentional refactoring, not as a way to fix recently written code.


Do not make the implementation of the last test final, but provide just enough code for this test to pass.

Write the code in any way you want, but do it fast. Once everything is green, we have confidence that there is a safety net in the form of tests. From this moment on, we can proceed to refactor the code. This means that we are making the code better and more optimal without introducing new features. While refactoring is in place, all tests should be passing all the time.

If, while refactoring, one of the tests failed, refactoring broke an existing functionality and, as before, changes should be reverted. Not only that, at this stage we are not changing any features, but we are also not introducing any new tests. All we're doing is making the code better while continuously running all tests to make sure that nothing got broken. At the same time, we're proving code correctness and cutting down on future maintenance costs.

Once refactoring is finished, the process is repeated. It's an endless loop of a very short cycle.

Speed is the key

Imagine a game of ping pong (or table tennis). The game is very fast; sometimes it is hard even to follow the ball when professionals play the game. TDD is very similar. TDD veterans tend not to spend more than a minute on either side of the table (test and implementation). Write a short test and run all tests (ping), write the implementation and run all tests (pong), write another test (ping), write the implementation of that test (pong), refactor and confirm that all tests are passing (score), and then repeat—ping, pong, ping, pong, ping, pong, score, serve again. Do not try to make the perfect code. Instead, try to keep the ball rolling until you think that the time is right to score (refactor).


Time between switching from tests to implementation (and vice versa) should be measured in minutes (if not seconds).

It's not about testing

T in TDD is often misunderstood. TDD is the way we approach the design. It is the way to force us to think about the implementation and what the code needs to do before writing it. It is the way to focus on requirements and the implementation of just one thing at a time—organize your thoughts and better structure the code. This does not mean that tests resulting from TDD are useless—they are far from that. They are very useful and they allow us to develop with great speed without being afraid that something will be broken. This is especially true when refactoring takes place. Being able to reorganize the code while having the confidence that no functionality is broken is a huge boost to its quality.


The main objective of TDD is testable code design with tests as a very useful side product.
You have been reading a chapter from
Test-Driven Java Development, Second Edition - Second Edition
Published in: Mar 2018
Publisher: Packt
ISBN-13: 9781788836111
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime