In this series of articles, we'll look at software testing and why you might want to do it. Later on, we'll discuss the specifics of unit testing, integration testing, functional testing, and acceptance testing. In this article, we'll talk about why you should test things. We'll also discuss test-driven development (TDD). In later articles, we'll see how to do automated unit testing, integration testing, functional testing, and acceptance testing using PhpUnit and Codeception.
If you're a web designer, rather than a developer, you might be tempted to tune out here, but designs need to be tested too. Your design needs to work on various platforms. You need to know that things work the way they should, preferably before deployment. Does the navigation work? Do the links all take you to the correct pages both on and off your site. Do the forms and their buttons work? If there's a "Reset" button on a form, does it clear the fields? If the user clicks on the "Submit" button without filling one or more required fields, do they get clear feedback about what's wrong? Are the other fields still filled in so they don't have to re-enter everything? For designers, the early articles in this series about unit testing and functional testing and integration testing won't be of much use. The later articles on acceptance testing, though, are going to present some automated testing ideas that will make any designer's life a lot easier.
The fact is, that everyone needs to test. Sometimes, you have to test things manually, but the more automated testing can you do the better. It's obvious that everything needs to be tested before the first deployment of a web site, but the best reason for automated testing is that web sites are almost never static — they change constantly, and every change risks breaking something you built earlier. I can't emphasize this enough: the level of comfort you get from having a solid set of automated tests that will make sure that changes to your code or web site haven't broken anything will change your life. Running tests to make sure recent changes haven't broken the code is called "regression testing."
There's and excellent article on the value of TDD on The QA Lead web site: Statistics & Studies: The Benefits Of Test Driven Development. The author (Ben Aston) looked at the empirical evidence for the claims people have made about TDD.
I encourage you to read the article and the studies it links to.
Overall, the results reported for TDD in the article are pretty impressive. Here's a quick summary of the findings (as I interpret them):
- TDD may or may not increase coding time by 15-35%. Some of the programmers involved were new to TDD, and the time was measured by asking managers for their opinions on it. There was a consensus that any time lost was offset by improved quality as well as reduced time to fix problems and add enhancements.
- There are a *lot* fewer bugs in code developed with TDD. One study by Microsoft reported a 60-90% drop in "bug density" in TDD code.
- The quality of TDD code is better overall (in addition to the lower bug density, it did a better job of fulfilling project requirements).
- TDD results in simpler, more robust designs.
- A significant number of coders reported some difficulty in switching to TDD.
What is Test-driven Development?
There are many sources that describe test-driven development (TDD) on the web. I think this article from freeCodeCamp is one of the best (you'll have to create an account with Medium if you haven't already). The article at The QA Lead also has a clear definition of TDD and how it differs from traditional development.
In short, TDD can be boiled down to three rules:
- When you want to create or improve something, create tests first that fail, but will test the behavior you want to see..
- Write the code and work on it until the tests pass.
- When the code passes the tests, stop what you're doing and create a new test.
Notice that this is different from the traditional method where you create things first, then figure out how to test them. The problem with that method is that you often design things so that they are untestable. It's frustrating to discover that you've done this, and it's tempting to give up on testing altogether at that point.
The good news about TDD is that once a stage of your project is finished, you already have a complete set of tests for it. Any time you add another stage or make changes to the original stage, you can quickly and easily run those tests to make sure you haven't broken anything.
TDD has several variations and offshoots. You can read about them in web articles about TDD, but they're beyond the scope of this article.
Test-driven Development for the Non-coder
At this point, you might be saying, "I can't code, so TDD is not an option for me." The fact is that the tests don't have to be in code and the testing can be manual, rather than automated. You can write down what you want to happen, and after working on it, you can test manually to see that your work passes the test your wrote down. Over time, you'll have a really useful list of all the things that you need to test before deploying any changes.
I have to admit that I'm not very good about following the three TDD rules in the section above (or any sensible rules for software development, for that matter). When I have an idea for an extra, or an improvement to an existing extra, I have an overwhelming urge to jump in and implement it. More than anything, this has taught me the value of TDD. When I start to develop code to test an extra, I very often find that I have to redesign it so it can be tested. Every time this happens, I find that the new code is better. It's more modular, it's more immune to errors, it's much more robust, and it's infinitely more readable.
Readability is often underrated in software development. I recently had to work on an extra I wrote seven years ago. I had to spend two full days just figuring out how my own code worked before I could even begin work, and I ended up making some breaking changes because I didn't fully understand the code.
If I had used TDD on the project, it would have been very clear from the start. Working on tests for the project has improved it to the point that the next time I come back to it, things will be much easier. Using TDD to begin with, would have slowed me down a little, but it would have saved me a lot of time in the long run. I also would have avoided some very frustrating work trying to locate the cause of the breaking changes since decent tests would have immediately pinpointed any problems.
In the next article in this series, we'll look at the definitions of unit testing, integration testing, functional testing, and acceptance testing.
Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)