User Guide Behavior Driven Design Library

Ideas

Behavior-driven development BDD is an agile software development process that encourages collaboration among developers, quality assurance experts, and customer representatives in a software project. It encourages teams to use conversation and concrete examples to formalize a shared understanding of how the application should behave. It emerged from test-driven development TDD. Behavior-driven development combines the general techniques and principles of TDD with ideas from domain-driven design and object-oriented analysis and design to provide software development and management teams with shared tools and a shared process to collaborate on software development.

A separate subcategory of behavior-driven development is formed by tools that use specifications as an input language rather than user stories. An example of this style is the RSpec tool that was also originally developed by Dan North.

Specification tools do not use user stories as an input format for test scenarios but rather use functional specifications for units that are being tested. These specifications are often more technical than user stories and are usually less convenient for communication with business personnel than are user stories.

requirements-vs-bdd

You want to:

  • Track Requirements

  • Review Requirements

  • Decompose Requirements

  • Communicate With Stakeholders

  • Connect Requirements to Tests

  • Prioritize Requirements

Specifications by Example

Features

A behavior-driven development BDD library that provides a custom extension based on the JUnit 5 Jupiter Extension Model. This library can be used to create and run features, stories and behaviors as BDD specification tests.

The library promotes a test engineer approach. The test cases are programmed against the system under development. Upon execution, the living documentation of all features, and their associated stories are generated. This document describes the behavior of the system as it is tested.

We believe that agile teams should write source code and tests. Unit tests shall validate the internal quality of the application.

Integration tests verify that requirements are implemented in the solution. Integration tests shall be derived from acceptance criteria formulated as specification by example [1, 2]. Seldom can users or stakeholders invest the time and learn the capabilities to formulate maintainable and binding acceptance tests. They are the domain know-how experts and rarely software specialists.

Software developers should write all acceptance tests together with domain experts [3, 4]. The acceptance tests should generate legible living documentation. Stakeholders use this documentation for feature review and acceptance decisions.

The library is implemented as an extension to the de facto standard JUnit5 for unit testing in the Java ecosystem.

Tags and identifiers are supported for regulatory aspects and traceability.

Scenarios

@ExtendWith(StoryExtension.class)
@Story(value = "Return go back to the stockpile", description = "As a store owner, in order to keep track of stock, I want to add items back to stock when they're returned.")
public class StoreTestStoryOne {
    @Scenario("Refunded items from the customer should be returned to stock")
    public void refundAndRestock(Scene scene) {
        scene.given("that a customer previously bought a black sweater from me",
                t -> t.put("store", new Store(0, 4).buyBlack(1))).
            and("I have three black sweaters in stock",
                t -> assertEquals(3, t.<Store>get("store").blacks(),
                "Store should carry 3 black sweaters")).

            when("the customer returns the black sweater for a refund",
                t -> t.<Store>get("store").refundBlack(1)).

            then("I should have four black sweaters in stock",
                t -> assertEquals(4, t.<Store>get("store").blacks(),
                "Store should carry 4 black sweaters")).
            run();
    }

    @Scenario("Replaced items should be returned to stock")
    public void replaceAndRestock(Scene scene) {
        scene.given("that a customer previously bought a blue garment from me",
                t -> t.put("store", new Store(3, 3).buyBlue(1))).
            and("I have two blue garments in stock",
                t -> assertEquals(2, t.<Store>get("store").blues(),
                "Store should carry 2 blue garments")).
            and("three black garments in stock",
                t -> assertEquals(3, t.<Store>get("store").blacks(),
                "Store should carry 3 black garments")).

            when("she returns the blue garment for a replacement in black",
                t -> t.<Store>get("store").refundBlue(1).buyBlack(1)).

            then("I should have three blue garments in stock",
                t -> assertEquals(3, t.<Store>get("store").blues(),
                "Store should carry 3 blue garments")).
            and("two black garments in stock",
                t -> assertEquals(2, t.<Store>get("store").blacks(),
                "Store should carry 2 black garments")).
                run();
    }
}

Get Started

  1. Add the library to your Gradle or maven build.

  2. Write your scenarios as test methods as shown in the above examples.

  3. Run your JUnit 5 tests.

The provided utilities generate JSON and AsciiDoc reports as living documentation.

Concepts

The behavior-driven development library defines the following concepts:

  • A feature describes a high-level function of the system. A feature annotation @feature allows the textual description of a feature and supports additional information such as an identifier or a set of tags. A feature is defined a package level.

  • A story describes a specific function of the system. A story annotation @story allows the textual description of a story and supports additional information such as an identifier or a set of tags. A feature is defined a class level.

  • A scenario describes a specific flow of a story. A scenario annotation @scenario allows the textual description of a scenario. A scenario is defied at method level.

  • Acceptance criteria are documented together with the given and when stages inside the method using the bdd library.

We believe that the three level hierarchy feature - story - scenario is enough to describe the requirements of regular software products.

Beware that feature and story as used in agile development approaches, such as Scrum, are work break-down structures. They are not a requirement repository.

You can change the content and the acceptance criteria of stories over the development cycle. No information is available in a backlog or JIRA, which variant is now the one implemented in the system.

More examples are available as unit tests.

References

[1] G. Adzic, Bridging the Communication Gap. Neuri Limited, 2009 [Online]. Available: https://www.amazon.com/dp/B008YZ993W/

[2] G. Adzic, D. Evans, and T. Roden, Fifty Quick Ideas To Improve Your Tests. Neuri Consulting LLP, 2015 [Online]. Available: https://www.amazon.com/dp/0993088112

[3] L. Crispin, Agile testing. Addison-Wesley, 2009 [Online]. Available: https://www.amazon.com/dp/0321534468

[4] J. G. Gregory and L. Crispin, More Agile Testing. Addison-Wesley Professional [Online]. Available: https://www.amazon.com/dp/0321967054