Introduction to TDD and BDD using python

Thu March 31 2016

John Roa

Full Stack Developer and Tech Lead
Associate.io

TDD
(Test Driven Deveopment)

"approach to development which combines test-first development where you write a test before you write just enough production code to fulfill that test and refactoring.

“The act of writing a unit test is more an act of design than of verification. It is also more an act of documentation than of verification. The act of writing a unit test closes a remarkable number of feedback loops, the least of which is the one pertaining to verification of function” - Robert C. Martin

Traditional software process

Design

Implement

Test

Traditional software process

Issues

  • Long phase execution
  • Manual testing
  • Lost or regression bugs
  • The bigger the codebase the longer the time to test and more probability to break things

TDD Flow

Test / Design

Implement

Benefits

  • Much less regression test bugs
  • Drastically reduced time to identify issues
  • Easy refactoring verification.
  • Better software design.

Python testing tools

Unittest

Doctest

py.test

Nose
Tox
Unittest2
Mock

Lets see some code

import unittest
from operations.operations import factorial, summation


class TddInPythonExample(unittest.TestCase):

    def test_factorial_operation_returns_correct_result(self):
        result = factorial(2)
        self.assertEqual(2, result)

    def test_summation_operation_returns_correct_result(self):
        result = summation(2)
        self.assertEqual(3, result)

test_operations.py

# coding=utf-8


def factorial(number):
    return 0


def summation(number):
    return 0

operations.py

/usr/bin/python /Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py --multiproc 
--qt-support --client 127.0.0.1 --port 64753 --file /Applications/PyCharm.app/Contents
/helpers/pycharm/utrunner.py /Users/jhonjairoscalablepath/PycharmProjects/
python-lettuce-sample-2/tests/test_operations.py::TddInPythonExample::
test_summation_operation_returns_correct_result true
Testing started at 4:42 PM ...
pydev debugger: process 55353 is connecting
Connected to pydev debugger (build 143.1919)


Failure
Traceback (most recent call last):
  File "/Users/jhonjairoscalablepath/PycharmProjects/python-lettuce-sample-2/tests
/test_operations.py", line 13, in test_summation_operation_returns_correct_result
    self.assertEqual(3, result)
AssertionError: 3 != 0


Process finished with exit code 0

Test fail !!! :(

Don't be sad!

Now you have things to do :D

operations.py

# coding=utf-8


def factorial(number):
    number = int(number)
    if (number == 0) or (number == 1):
        return 1
    else:
        return number*factorial(number-1)


def summation(number):
    number = int(number)
    if number == 0:
        return 0
    else:
        return number+summation(number-1)
/usr/bin/python /Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py --multiproc 
--qt-support --client 127.0.0.1 --port 64816 --file /Applications/PyCharm.app/
Contents/helpers/pycharm/utrunner.py /Users/jhonjairoscalablepath/PycharmProjects/
python-lettuce-sample-2/tests/test_operations.py::TddInPythonExample::
test_summation_operation_returns_correct_result true
Testing started at 4:45 PM ...
pydev debugger: process 55376 is connecting

Connected to pydev debugger (build 143.1919)

Process finished with exit code 0

Test pass !!! :'D

Source code

ATDD
(Acceptance Test Driven Development)

is a communication tool between the customer, developer, and tester to ensure that the requirements are well-defined

"Customer"

or
Product Owner

Tester

Developer

requirements written as acceptance tests

focus on writing acceptance tests before developers begin coding

"the product owner, customer or domain expert is able to specify new functionality by writing new acceptance tests or test cases, without needing to consult developers"

BDD
(Behavior Driven Deveopment)

"is a process designed to aid the management and the delivery of software development projects by improving communication between engineers and business professionals."

BDD: Two parts

  • using examples written in ubiquitous language to illustrate behaviors (how users will interact with the product).

 

  • Using those examples as the basis of automated tests.
    • Checking functionality for the user.
    • Ensures the system works as defined by the business.

"tests of any unit of software should be specified in terms of the desired behavior of the unit"

"business analysts and developers should collaborate in this area and should specify behavior in terms of user stories"

Traditional development process

1. Chris tells a business analyst how he would like the feature to work.

 

2. The business analyst translates Chris’s requests into a set of requirements for the developers, describing what the software should do. These requirements are written in English and stored in a Microsoft Word document.

 

3. The developer translates the requirements into code and unit tests—written in Java, C#, or some other programming language—in order to implement the new feature.

Traditional development process

4. The tester translates the requirements in the Word document into test cases, and uses them to verify that the new feature meets the requirements.

 

5. Documentation engineers then translate the working software and code back into plain English technical and functional documentation.

Doing BDD...

How do I do that?

Writing stories

'Each feature is captured as a “story”, which defines the scope of the feature along with its acceptance criteria'

Title (one line describing the story)
 
Narrative:
As a [role]
I want [feature]
So that [benefit]
 
Acceptance Criteria: (presented as Scenarios)
 
Scenario 1: Title
Given [context]
  And [some more context]...
When  [event]
Then  [outcome]
  And [another outcome]...
 
Scenario 2: ...

Gherkin language

"lets you describe software’s behavior without detailing how is implemented."

Gherkin language purposes

  • Documentation
  • Automated tests.

Gherkin language source file

1: Feature: Some terse yet descriptive text of what is desired
 2:   Textual description of the business value of this feature
 3:   Business rules that govern the scope of the feature
 4:   Any additional information that will make the feature easier to understand
 5: 
 6:   Scenario: Some determinable business situation
 7:     Given some precondition
 8:       And some other precondition
 9:      When some action by the actor
10:       And some other action
11:       And yet another action
12:      Then some testable outcome is achieved
13:       And something else we can check happens too
14: 
15:   Scenario: A different situation
16:       ...

Example: Gherkin language source file

Story: Account Holder withdraws cash
 
As an Account Holder
I want to withdraw cash from an ATM
So that I can get money when the bank is closed
 
Scenario 1: Account has sufficient funds
Given the account balance is \$100
 And the card is valid
 And the machine contains enough money
When the Account Holder requests \$20
Then the ATM should dispense \$20
 And the account balance should be \$80
 And the card should be returned
 
Scenario 2: Account has insufficient funds
Given the account balance is \$10
 And the card is valid
 And the machine contains enough money
When the Account Holder requests \$20
Then the ATM should not dispense any money
 And the ATM should say there are insufficient funds
 And the account balance should be \$20
 And the card should be returned
...

Example: Gherkin language source file

Story: Account Holder withdraws cash
 
As an Account Holder
I want to withdraw cash from an ATM
So that I can get money when the bank is closed
 
....
 
Scenario 3: Card has been disabled
Given the card is disabled
When the Account Holder requests \$20
Then the ATM should retain the card
And the ATM should say the card has been retained
 
Scenario 4: The ATM has insufficient funds
...

'Behaviour-driven development is an “outside-in” methodology. It starts at the outside by identifying business outcomes, and then drills down into the feature set that will achieve those outcomes.'

BDD: Activities and outcomes

"Executable specifications are about communication as much as they are about validation"

don’t write unit tests, write low-level specifications

Unittest

Doctest

py.test

Nose
Tox
Unittest2
Mock

steps.py

transfer.feature

Benefits

MUCH BETTER COMMUNICATION WITH BUSINESS PEOPLE!!!

  • Reduced waste
  • Reduced costs
  • Easier and safer changes
  • Faster releases

Challenges

  • High bussiness engagement
  • BDD works best in agile contexts
  • Poorly written tests can lead to higher test-maintenance costs

Python BDD tools

Lettuce

Behave

Let's see some code...

Project structure

factorial.feature

Feature: Compute factorial
    In order to play with Lettuce
    As beginners
    We'll implement factorial

    Scenario: Factorial of 0
        Given I have the number 0
        When I compute its factorial
        Then I see the number 1

    Scenario: Factorial of 1
        Given I have the number 1
        When I compute its factorial
        Then I see the number 1

    Scenario: Factorial of 2
        Given I have the number 2
        When I compute its factorial
        Then I see the number 2

    Scenario: Factorial of 3
        Given I have the number 3
        When I compute its factorial
        Then I see the number 6

    Scenario: Factorial of 4
        Given I have the number 4
        When I compute its factorial
        Then I see the number 24

steps.py

# coding=utf-8
from lettuce import world, step
from operations.operations import factorial, summation


@step('I have the number (\d+)')
def have_the_number(step, number):
    world.number = int(number)


@step('I compute its factorial')
def compute_its_factorial(step):
    world.number = factorial(world.number)


@step('I compute its summation')
def compute_its_factorial(step):
    world.number = summation(world.number)


@step('I see the number (\d+)')
def check_number(step, expected):
    expected = int(expected)
    assert world.number == expected, \
        "Got %d" % world.number

operations.py

# coding=utf-8


def factorial(number):
    number = int(number)
    if (number == 0) or (number == 1):
        return 1
    else:
        return number*factorial(number-1)


def summation(number):
    number = int(number)
    if number == 0:
        return 0
    else:
        return number+summation(number-1)

Source code

TDD vs BDD

TDD

Product Owner

Tester

Developer

TDD

"We have a coverage of 95% of the code!!!"

Emmm ok, cool.

BDD

Product Owner

Tester

Developer

BDD

"We have completed 95% of the features!!!"

THAT'S AWESOME!!!!!

Yes, I can notice that.

"Not only test your code at the granular level with unit tests, but also test your application end to end, using acceptance tests"

TDD

"the unit tests of a class"

"the specifications of the behavior of the class" 

BDD

TDD

"focussed on developers and testers"

"focused on customer" 

BDD

TDD

"focussed on implementation"

"focused on behavior" 

BDD

TDD

"test code blocks"

"test what customer expects from the platform" 

BDD

Resources

More resources

Thanks!!!

Q & A

Introduction to TDD and BDD using python

By Jhon Jairo Roa

Introduction to TDD and BDD using python

Review of TDD and BDD main characteristics , how do they get along and how they are implemented in python

  • 4,027