Refactoring legacy code using automated acceptance tests

A question I often get asked as a consultant is how to maintain a legacy code base that has very little or no unit tests, or any automated tests for that matter. How do you start to refactor the code and introduce unit tests?

The problem with immediately adding unit tests to a unit test free legacy code base is the code won’t be testable (as it wasn’t test-driven), and it will require refactoring to make it so. But refactoring legacy code without unit tests as a safety net is risky and can easily stop your application and introduce bugs, so you’re in a catch-22.

A good solution to this problem is to write a few specific automated acceptance tests for the feature you would like to add unit tests to, before you write any unit tests.

For example, imagine you would like to add some unit tests to the registration feature of your application, you might automate four acceptance test scenarios:

Scenario One: User can register using valid credentials
Scenario Two: User can’t register using existing email address
Scenario Three: User can’t register without providing mandatory data
Scenario Four: User can’t register from a non-supported country

Before you make any changes to your code base, you must write and execute these scenarios until they are all passing.

Once they are all passing then you can start writing unit tests one by one until each passes. As you write unit tests and refactor your code as required, you should run your specific acceptance tests to ensure the high level functionality hasn’t been broken by your changes.

Once you have completed your unit tests you will have a set of unit tests and automated regression tests with code that supports both.

You can repeat this for each feature in your system, and slowly combine a few key scenarios into an end-to-end scenario that replicates a common user-journey throughout your application.

At the end of this process you will have cleaner code, a set of unit tests, a set of feature based acceptance tests and one or two end-to-end user journeys that you can execute against any change you make.

Paying down technical debt is hard, but following a methodological approach using automated acceptance tests as a safety net makes it practical to do so.

Is test management wrong?

I was somewhat confused by what was meant by the recent article entitled “Test Management is Wrong“. I couldn’t quite work out whether the author meant Test Management (the activity) is wrong, Test Managers (the people) are wrong or Test Management Tools (the things) are wrong, but here’s my view of these three things:

Test Management (the activity): now embedded in agile teams;
Test Managers (the people): on the way out; and
Test Management Tools (the things): gathering dust

Let me explain with an example. Most organizations see the benefit of agile ‘iterative’ development and have or are in the process of restructuring teams to work in this way. A typical transformation looks like this:

Agile Transformation

Instead of having three separate larger ‘analysis’, ‘development’ and ‘test’ teams, the organization may move to four smaller cross functional teams consisting of say one tech lead, one analyst, one tester and four programmers.

Previously a test manager managed the testing process (and testing team) probably using a test management tool such as Quality Centre.

Now, each agile team is responsible for its own quality, the tester advocates quality and encourages activities that build quality in such as accurate acceptance criteria, unit testing, automated acceptance testing, story testing and exploratory testing. These activities aren’t managed in a test management tool, but against each user story in a lightweight story management tool (such as Trello). The tester is responsible for managing his/her own testing.

Business value is defined and measured an iteration at a time by the team.

So what happens to the Analysis, Development and Test Managers in the previous structure? Depending on the size of the organization, there may be a need for a ‘center of excellent’ or ‘community practice’ in each of the areas to ensure that new ideas and approaches are seeded across the cross-functional teams. The Test Manager may be responsible for working with each tester in the teams to ensure this happens. But depending on the organization and the testers, this might not be needed. This is the same for the Analysis Manager, and to a lesser extent, the Development Manager.

Step by Step test cases (such as those in Quality Center) are no longer needed as each user story has acceptance criteria, and each team writes automated acceptance tests written for functionality they develop which acts as both automated regression tests and living documentation.

So the answer the author’s original message: no I don’t think test management is wrong, we just do it in a different way now.

Automated local accessibility testing using WAVE and WebDriver

I wrote a while back about automated WCAG 2.0 accessibility testing in our build pipeline.

My solution involved capturing the HTML of each unique page in our application visited via WebDriver, then navigating to the online WAVE tool to check the accessibility of each chunk of HTML, all done during a dedicated accessibility stage of our build pipeline.

That was working pretty well until I noticed our IP address was starting to become blocked by WAVE due to a unreasonable number of checks… Doh!

Locally we’ve all been using the Firefox WAVE toolbar, as it’s very easy to run against a locally running instance of our application. Which made me think: how do I automate the Firefox WAVE toolbar to avoid having to use the WAVE web site alltogether?

Today I changed our accessibility tests to use the WAVE toolbar. It was a bit of a pain since we use Windows and the WAVE toolbar seems to be broken in configuring Firefox shortcut keys to trigger accessibility checks.

What I ended up doing is firing the keystrokes needed to run the check via the Tools menu in Firefox. I then check the DOM to ensure there are no WAVE errors and screenshot it and fail the test if there are. Quite simple really, and it works very reliably and quickly.

Makes me think I should have done this to start with, but a good outcome nonetheless.

Some C# WebDriver code to do this follows. This should be easy to adapt to another language.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using System.Drawing.Imaging;

namespace Dominos.OLO.Html5.Tests.Acceptance
{
    [TestClass]
    public class AccessibilityTests
    {
        [TestMethod]
        public void AccessibilityTest()
        {
            var profile = new FirefoxProfile();
            profile.AddExtension("wavetoolbar1_1_8_en.xpi");
            var driver = new FirefoxDriver(profile);

            driver.Navigate().GoToUrl("http://apple.com");

            var b = driver.FindElement(By.TagName("body"));
            b.SendKeys(Keys.Alt + "T");
            b.SendKeys(Keys.ArrowDown);
            b.SendKeys(Keys.ArrowDown);
            b.SendKeys(Keys.ArrowDown);
            b.SendKeys(Keys.ArrowDown);
            b.SendKeys(Keys.ArrowRight);
            b.SendKeys(Keys.Enter);

            var waveTips = driver.FindElements(By.ClassName("wave4tip"));
            if (waveTips.Count == 0) Assert.Fail("Could not locate any WAVE validations - please ensure that WAVE is installed correctly");
            foreach (var waveTip in waveTips)
            {
                if (!waveTip.GetAttribute("alt").StartsWith("ERROR:")) continue;
                var fileName = String.Format("{0}{1}{2}", "WAVE", DateTime.Now.ToString("HHmmss"), ".png");
                var screenShot = ((ITakesScreenshot)driver).GetScreenshot();
                screenShot.SaveAsFile(fileName, ImageFormat.Png);
                Assert.Fail("WAVE errors were found on the page. Please see screenshot for details");
            }
        }
    }
}

and finally the resulting screenshot:

Apple WAVE check results

Why I don’t like Jasmine JavaScript unit tests (for MVC web apps)

Update 11-Feb-2013: After some feedback, I would like to clarify what I am talking about here: I am talking from experience in applications not purely written in JavaScript: for example a MVC application written with say C# with JavaScript added to pages.

I’m really not a big fan of Jasmine JavaScript unit tests for applications not written purely in JavaScript. Here’s why:

jasmine logo

Most modern web applications use JavaScript as a way to provide client side validation and interaction. Most of this JavaScript manipulates the Document Object Model (DOM) of the browser, therefore the JavaScript is coupled to the DOM using ids or classes of elements.

As most web pages are dynamically rendered by the server, Jasmine, the JavaScript unit test framework, can’t run against the ‘real’ DOM as it appears in the application, so what it does is duplicates parts of the DOM to test the JavaScript is working properly based upon this duplication.

As there’s no reliance on the real application or its DOM, these tests run super fast, you can run thousands of JavaScript tests in seconds which is pretty amazing.

The problem becomes that over time the real DOM in the application is changed but the Jasmine tests and its own duplicated DOM is not! This means that often I find that all Jasmine tests pass (as they have to for a new version to be deployed to QA) but the JavaScript doesn’t work in the application because an id or class name has been changed and someone ‘forgot’ to update the Jasmine tests.

Tests that don’t pick up valid errors are worthless, and I continually find myself getting annoyed that all the Jasmine tests have passed, but JavaScript is broken and our application doesn’t work.

Another downside is that Jasmine tests are only as good as the JavaScript engine they are run against. We run our Jasmine tests in a headless PhantomJS browser, which is fast, but most of our JavaScript bugs are found in Internet Explorer, particularly earlier versions of it, so Jasmine tests again are worthless.

I don’t know of a way to overcome these downsides to Jasmine that I have mentioned. What we do have is a suite of end to end acceptance tests that run in 5 different ‘real’ browsers that check the JavaScript works correctly. Whilst these take 8 minutes to run per browser, they pick up a lot more JavaScript issues than Jasmine.

I am not still not sure whether it is worth investing the time and effort in Jasmine tests when they don’t provide sufficient confidence that our application ‘works’.

What have others experiences been with Jasmine JavaScript unit testing?

Automated WCAG 2.0 accessibility testing in the build pipeline

The web application I am currently working on must meet accessibility standards: WCAG 2.0 AA to be precise. WCAG 2.0 is a collection of guidelines that ensure your site is accessible for people with disabilities.

An example of poor accessibility design is missing an alt tag on an image, or not specifying a language of a document, eg:

<HTML lang="fr">

Building Accessibility In

Whilst later we’ll do doing accessibility assessments with people who are blind or have low vision, we need to make sure we build accessibility in. To do this, we need automated accessibility tests as part of our continuous integration build pipeline. My challenge this week was to do just this.

Automated Accessibility Tests

First I needed to find a tool to validate against the spec. We’re developing the web application locally so we’ll need to run it locally. There’s a tool called TotalValidator which offers a command line tool, the only downside is the licensing cost, as to use the command line version you need to buy at least 6 copies of the tool at £25 per copy, approximately US$240 in total. There’s no trial of command line tool unless you buy at least one copy of the pro tool at £25. I didn’t want to spend money on something that might not work so I kept looking for alternatives.

There are two sites I found that validate accessibility by URL or supplied HTML code: AChecker and WAVE.

AChecker: this tool which works really well. It even supplies an REST API, but I couldn’t find a way to call the API to validate HTML code (instead of by URL) which is what I would like to do. The software behind AChecker is open source (PHP) so you can actually install your own version behind your firewall if you wish.

WAVE: a new tool recently released by WebAim: Web Accessibility in Mind. Again this is an online checker that allows you to validate by URL or HTML code supplied, but unfortunately there’s no API (yet) and the results aren’t as easy to programatically read.

My Solution

The final solution I came up with is a specific tagged web accessibility feature in our acceptance tests project. This has scenarios that use WebDriver to navigate through our application capturing the HTML source code from each page visited. Finally, it visits the AChecker tool online and validates each piece of HTML source code it collected and fails the build if any accessibility problems are found.

AChecker Results

Build Light

We have a specific build light that runs all the automated acceptance tests and accessibility tests. If any of these fail, the light goes red.

Build Status Lights

It’s much better if it looks like this:

Build Lights All Green

Summary

It was fairly easy to use an existing free online accessibility checker to validate all HTML code in your local application, and make this status highly visible to the development team. By building accessibility in, we’re reducing the expected number of issues when we conduct more formal accessibility testing.

Bonus Points: faster accessibility feedback

Ideally, as a page is being developed, the developer/tester should be able to check accessibility (rather than waiting for the build to fail). The easiest way I have found behind a firewall is to use the WAVE Firefox extension, which displays errors as you use your site. Fantastic!

(Apple and Microsoft each have one known accessibility problem, Google has nine!)

Apple.com accessibility

Mobile apps still need automated tests

Jonathan Rasmusson recently wrote what I consider to be quite a contentious blog post about iOS application development titled “It’s not about the unit tests”.

“…imagine my surprise when I entered a community responsible for some of the worlds most loved mobile applications, only to discover they don’t unit test. Even more disturbing, they seem to be getting away with it!”

Whilst I agree with the general theme of the blog post which is change your mind, challenge assumptions:

“All I can say is to keep growing sometimes we need to challenge our most cherished assumptions. It doesn’t always feel good, but that’s how we grow, gain experience, and turn knowledge into wisdom.”

“The second you think you’ve got it all figured out you’ve stopped living.”

I don’t agree with the content.

Jonathan’s basic premise is that you can get away with little or no unit testing for your iOS application for a number of reasons including developing for a smaller screen size, no legacy, one language, visual development and developing on a mature platform. But the real reason that iOS get away with it is by caring.

“These people simply cared more about their craft, and what they were doing, than their contemporaries. They ‘out cared’ the competition. And that is what I see in the iOS community.”

But in writing this post, I believe he missed two critical factors when deciding whether to have automated tests for your iOS app.

iOS users are unforgiving

If you accidentally release an app with a bug, see how quickly you’ll start getting one star reviews and nasty comments in the App Store. See how quickly new users will uninstall your app and never use it again.

The App Store approval process is not capable of supporting quick bug fixes

Releasing a new version of your app that fixes a critical bug may take you 2 minutes (you don’t even need to fix a broken test or write a new test for it!) but it then takes Apple 5-10 business days to release it to your users. This doesn’t stop the one star reviews and comments destroying your reputation in the meantime.

Case in Point: Lasoo iPhone app

I love the Lasoo iPhone app, because it allows me to read store catalogs on my phone (I live in an apartment block and we don’t get them delivered). Recently I upgraded the app and then tried to use it but it wouldn’t even start. I tried the usual close/reopen, delete/reinstall but still nothing. I then checked the app store:

Lasoo iPhone app reviews
Lasoo iPhone app reviews

Oh boy, hundreds of one star reviews within a couple of days: the app is stuffed! I then checked twitter to make sure they knew it was broken, and to my surprise they’d fixed it immediately but were waiting for Apple to approve the fix.

I can’t speculate on whether Lasoo care or not about their app, but imagine for a second if they had just one automated test, one automated test that launched the app to make sure it worked, and it was run every time a change, no matter how small, was made. That one automated test would have saved them from hundreds of one star reviews and having to apologize to customers on twitter whilst they waited for Apple to approve the fix.

Which raises another point:

“[Apple] curate and block apps that don’t meet certain quality or standards.”

The Lasoo app was so broken it wouldn’t even start, so how did it get through Apple’s approval process for certain quality or standards?

Just caring isn’t enough to protect you from introducing bugs

We all make mistakes, even if we care. That’s why we have automated tests, to catch those mistakes.

Not having automated tests is a bit like having unprotected sex. You can probably get away with it forever if you’re careful, but the consequences of getting it wrong are pretty dramatic. And just because you can get away with it doesn’t mean that other people will be able to.