Go to main contentGo to footer
test
|
14 March 14

The joys and pains of testing: a crash course for clients

However 'distant' and daunting the topic may seem, testing is something to discuss with the people you're working with as early as possible. The safety of the entire product is at stake!

Lorenzo MasiniDeveloper

So what are these benefits?

In general, the goal of testing is to increase the developer's confidence in the code produced. By developer I don't just mean the original author of the code, but anyone who has to work on it from that point on.

This confidence pays off at every stage of the product's production cycle:

  • Fewer surprises: tested software holds very few surprises when it's released to production. Each feature has already been thoroughly verified during development, precisely thanks to the tests;
  • Maintainability: software is maintainable over time when you can carry out continuous refactoring to improve its internal architecture, but refactoring is impossible or very expensive without a broad test suite that prevents regressions in the system's existing features;
  • Documentation: while traditional written code documentation often risks no longer reflecting reality because it hasn't been updated, a descriptive test suite provides the best live documentation of how to use a software component.

Better design with TDD

Writing tests before actually writing the feature is the foundation of a development methodology called TDD, Test Driven Development.

TDD is based on 3 "simple" steps:

  1. Write a test that describes the desired feature;
  2. Write the minimum code needed to make the test pass;
  3. Refactor if necessary (making sure the tests still pass when you're done);

While writing tests isn't all that hard for a developer and brings all the benefits mentioned, starting to work in TDD is a whole different story! It takes time and persistence to reverse the traditional code-writing flow and start thinking through tests.

Starting from the tests forces you to define, up front, concrete use cases and convenient interfaces through which the outside world will use the desired feature. In other words, it forces you to constantly think about what you're doing.

What's the result of all this enormous effort? A cleaner, more modular overall design, made up of more cohesive, decoupled sub-components with better-defined responsibilities.

Thinking like a stakeholder with BDD

Even when working in TDD, professional habit means that a developer building a feature requested by the client often tends to start "from the foundations" and gradually move up to higher layers of abstraction.

It's a perfectly valid practice, but it carries a significant risk: losing sight along the way of the ultimate purpose of what you're building.

It may seem obvious, of course, but with complex tasks, involving dozens of "moving" parts and conditions to account for, it's a very real risk not to be underestimated, and it often leads to needlessly generalizing the underlying layers.

The most insidious cause of overengineering is over-generalizing.

The natural extension of TDD is called Behavior Driven Development, which tries to solve the problem by once again reversing the more "natural" but error-prone approach.

When developing in BDD, you always start from a concrete use case. This use case, which in more agile terminology is called a story, is simply a high-level specification, written together with the stakeholder and expressed in business-oriented rather than technical language, for example:

"As a user, I want to be able to log in with my email and password so that I can access my orders"

The goal is to highlight the ultimate purpose, leave no room for interpretation and put the emphasis on what to build rather than how.

The story is then also implemented as a high-level test, and you work toward it step by step following TDD rules, producing the minimum number of core sub-features needed to make it pass.

In other words, working by use cases in BDD means you always have an extraordinary Ariadne's thread that keeps you on course without getting lost in the maze of the code you produce.

Untested code is broken code®

After this quick "high-level" overview, we hope that anyone, including people from outside our industry, can at least sense the enormous risks taken on by anyone who starts a new project without requiring a test suite, and how this decision has a direct impact on the final product in terms of maintainability, documentation and overall design quality.

Testing is more an art than a science. The next post on testing will be more technical, and we'll try to describe concretely how we approach the topic in a Rails context.

footer