How to Create a Better Software

From Test-Driven Development to Behavior-Driven Development

The highly competitive and globalized software market is creating pressure on software companies. It is critical to continuously decrease time-to-market and reduce development costs to be successful.

Development should focus on the purpose of your work to people who will use it.

Test-Driven Development

TDD approach based on two fundamental moments — tests make software and software is developed iteratively. Test-driven development is rather a paradigm than a process. It describes the cycle of writing a test first, and application code afterwards — followed by an optional refactoring. For each test case you perform the following steps:

  1. Write a test script and make sure it fails.
  2. Develop a clear solution to make the script pass.
  3. Clean your code.

Once you are done, write another test until the feature is complete.

A Practical Example

I’ve written the following example in Java using JUnit testing framework .

Let’s say our example app convert Roman numerals to Arabic. We want to initialize a Roman with a string (e.g. “MMVI”), and make sure that we can retrieve the correct Arabic numerals afterwards:

@Test
public final void checkMMVI() {
Assert.assertEquals(2006, RomanToArabic.convertRomanToArabic(“MMVI”));
}

Running this test yields the error that our app doesn’t know how to convert numerals:

Invalid input format

Our test fails, so we’re on the right track! When you write tests, always watch them fail first:

JUnit test execution report

This guarantees that you don’t test something that already works and you’ll notice when there’s something wrong with your test. You write tests for code that doesn’t exist yet, so they always need to fail first:

JUnit test execution error message

Falling test creates a need. This is like someone asks your app for that need and your app failing to fulfill it. And that’s a real problem of that virtual user of your app, which you should solve by adjusting your application.

Let’s implement our class RomanToArabic now. We need to implement a constructor that accepts the roman numeral as argument:

public class RomanToArabic {
public static int convertRomanToArabic(java.lang.String romanNumerals) {
return 0;
}

Run the test again. Great, the test tells us what to do next:

JUnit Test execution error

By sticking to the easiest possible solution you should implement the algorithm for conversion. Ones you did this, test again:

According to the test-driven development, after you’ve reached a working solution it’s a time to refactor the code. Take your time, do it right.

What is effort?

Most apps start out as trivial and clean but end up as a swamp only a few moths later. Imagine a situation when you need to fix a critical issue in your source code, but unable to check fast does it work properly after the fix. You can hardly clean up the code because there’s no way of making sure that everything still works like before. And the only possibility to verify the fix is to spend days on manual check.

Test-driven development keeps you agile. You will be slower at first but you avoid being stuck in the most critical situation.

Test-Driven Development and continuous integration

The more tests you have, the longer they take to run. A good solution is to run only the tests that correspond to your current feature and let the whole test suite run on a Continuous Integration system.

Behavior-Driven Development

The name test-driven development always cause confusion. How can you test something that’s not there yet? And it brings a lot of questions like what exactly to test, where to start, how much to test in one go.

Test-driven development focuses on the developer’s answer on these questions. Instead, behavior-driven development focuses on the users’ opinion on how they want your application to behave.

Behavior-driven development is a collection of tools and methodologies based on test-driven development. It has evolved out of established agile practices and automated acceptance testing. In BDD instead of writing tests you should think of specifying behavior. When your development is behavior-driven, you always start with the piece of functionality that’s most important to your user:

  • Find out the feature that’s most important.
  • Within this feature select the most important scenario.

Hands-on moments

Natural language usage. In behavior-driven development you specify Behavior in whole sentences. Not just the naming but also the code syntax should read naturally. BDD does not have any formal requirements for exactly how user stories must be written down, but it desirable to have a template that lets you describe features in natural language:

Story: Returns go to stock

In order to keep track of stock
As a store owner
I want to add items back to stock when they're returned

Scenario 1: Refunded items should be returned to stock
Given a customer previously bought a black sweater from me
And I currently have three black sweaters left in stock
When he returns the sweater for a refund
Then I should have four black sweaters in stock

Each story has a title and a short description of what the story is about. The format of this description is always the same:

  • In order to: describes a benefit. Helps to understand the why with a direct focus on motivation.
  • As a: target user. Defines who are your clients.
  • I want: what feature will be used. Focus on how the work gets done.

A story is always followed by a list of scenarios containing Given steps (what has happened before), When steps (what actions the user performs), and Then steps (the desired outcome for the user). And it’s all about context and causality.

This requirement makes things more concrete and has following benefits:

  • You test exactly what the sentence says. No more, no less.
  • Just by reading the sentence, you’ll understand what this behavior is about.
  • These specifications become regression tests. And when such regression test fails, you immediately see what behavior of your application is broken.

Tools like Cucumber or Jasmine that makes possible to test your natural language features automatically.

Conclusion

Behavior-driven development as “test-driven development done right”. It focuses on the purpose of your work to people who will use it. This way you will create better software and successfully address your customers’ needs.