Skip to content

Behavior Driven Development (BDD)

Cristiane Naves Cardoso edited this page Apr 8, 2021 · 5 revisions

Behavior Driven Development

BDD is a set of practices of Software Engineering that aims to improve the quality of the code and the delivery of correct software. BDD is based on agile and lean development techniques that aim at collaboration between developers and different stakeholders in the verification and validation process.

BDD proposes the use of a language that is understandable by all stakeholders. In this way, everyone involved will use this language to describe the software's functionalities, which will be described in several files ending with the suffix .feature. One of BDD's ideas is to use these files as a form of documentation and also to test the various behaviors of the software.

The scenarios are composed of several rules and each rule can be mapped to a method that will check if it is executed correctly.

Gherkin

For the creation of the scenarios, languages are used that can be understood by all stakeholders, an example is the Gherkin language.

A feature, using Gherkin, can be specified as follows (gherkin reference):

Feature: brief description of the functionality

Scenario: description of a specific feature scenario.

    Given a precondition

    And other precondition

    When an action occurs

    And another action takes place

    Then a testable result is obtained

Explicação detalhada das keywords

Feature

The purpose of the keyword feature is to give a high-level description of a system's functionality and to group the scenarios related to this feature.

Scenario

The Scenario keyword describes a business rule for functionality and consists of several Given/When/Then rules.

Given

Define an initial state before starting to test. In this step, object instances, database configurations, search for a web page can be made, among other configurations necessary to leave the system in an initial state. In the case of the simulation, in the Given step, all settings of the scenarios necessary to correctly execute the simulation are made.

When

Defines an event or an action to be performed on the system being tested. This action can be done by a person or by another system.

Then

Describes the expected result of performing the previous steps. In this step, the assert will be carried out to verify that the received output is equal to the output that was expected.

And

It serves as a synonym for the step before it and is used to avoid multiple writing of Given/When/Then.

How to create scenarios and tests using the BDD specification language

It is possible to create specifications for a robotic mission (scenarios) using a BDD specification language, in which case Gherkin will be used. For this we will use the pytest-bdd library.

The description of the scenarios will be made in a .feature file. Each .feature file is responsible for a certain functionality, and in that file it can describe various scenarios related to that particular functionality. The scenarios can be described as several Given, When and Then steps.

The Given steps will be used for setting up the scenarios, for example, instantiating a simulation, defining the necessary systems, adding components. The When step is responsible for running the simulation. Finally, the Then step is used to verify that the result of the execution came as expected.

In this project, the features are present in the tests/features folder. For each .feature file in that folder, there is a test file present in the tests/step_defs folder that checks each Given, When, Then step for each feature scenario.

There are also auxiliary methods to help create the scenarios and to help make the asserts.

The methods for creating scenarios are present in the file ScenarioCreationHelper.py in the folder tests/helpers and the class has methods to add components, to add POIs (Point of Interest), to add events, to add systems to the simulation, among others.

The methods to help with assertions are present in the file AssertionHelper.py also in the folder tests/helpers. The AssertionHelper class has several methods, among them, a method to verify that the camera has detected the person, a method to verify that the robot approximated a person, a method to verify if a collision has occurred, a method to verify if an entity is in a specific POI.

The simulations maps are made using the drawio. Examples of maps are present in the tests/data folder and in the simulator/resources/map folder.

To create a test using the BDD, you will first create a scenario, for example, the following scenario describes a robot in position 1.1 that remains stationary throughout the simulation, when the simulation is finished and a check is made, the robot needs be in position 1.1, otherwise an error has occurred. Example file: tests/feature/single_static_robot.feature

Feature: Single Static Robot
Scenario: Single static robot
   Given a map with one room
   And a robot with id 'robot' in position '1,1' inside the room
   When the robot stay still
   Then the robot with id 'robot' is in '1,1'

Soon after, a test file will be created to execute and verify each step present in the scenario above. Example file: tests/step_defs/test_single_static_robot.py.

scenarios('../features/single_static_robot.feature')
 
@pytest.fixture
def scenario_helper(simulation):
   return ScenarioCreationHelper(simulation)
 
@pytest.fixture
def assertion_helper(simulation):
   return AssertionHelper(simulation)
 
@given("a map with one room", target_fixture="simulation")
def map_with_one_room():
   config = {
       "context": "tests/data",
       "map": "one_room_map.drawio",
       "FPS": 60,
       "DLW": 10,
       "duration": 10
   }
   simulation = Simulator(config)
   return simulation
 
@given(parsers.parse("a robot with id '{robot}' in position '{position}' inside the room"))
def a_robot_in_given_position(scenario_helper: ScenarioCreationHelper, robot, position):
   pos = position.replace(' ', '').split(',')
   scenario_helper.set_position(robot, int(pos[0]), int(pos[1]))
 
@when("the robot stay still")
def stay_still(simulation):
   simulation.run()
 
@then(parsers.parse("the robot with id '{robot}' is in '{position}'"))
def check_the_robot_is_in_position(assertion_helper: AssertionHelper, robot, position):
   pos = position.replace(' ', '').split(',')
   assert assertion_helper.is_in_position(robot, (int(pos[0]),int(pos[1])))

The first step Given instantiates a simulation that uses a one_room_map.drawio map present in the tests/data folder. The second step Given configures the robot to be in position 1,1. The When step will run the simulation. The Then step will check if the robot is located at position 1,1.

Remembering that it is also necessary to create the drawio map with the robot and everything that is necessary.

After creating the scenario and the tests, just run pytest to check if everything is going through. .