Thu March 31 2016
Full Stack Developer and Tech Lead
Associate.io
"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
Design
Implement
Test
Issues
Test / Design
Implement
Unittest
Doctest
py.test
Nose
Tox
Unittest2
Mock
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 !!! :(
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
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"
"is a process designed to aid the management and the delivery of software development projects by improving communication between engineers and business professionals."
"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"
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.
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.
'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: ...
"lets you describe software’s behavior without detailing how is implemented."
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: ...
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
...
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.'
"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
MUCH BETTER COMMUNICATION WITH BUSINESS PEOPLE!!!
Lettuce
Behave
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)
Product Owner
Tester
Developer
TDD
"We have a coverage of 95% of the code!!!"
Emmm ok, cool.
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
http://inviqa.com/insights/bdd-guide
http://dannorth.net/introducing-bdd/
http://dannorth.net/whats-in-a-story/
http://pythonhosted.org/behave/philosophy.html
BDD Testing a Restful Web Application in Python
http://www.slideshare.net/Siddhi/test-driven-development-with-python
http://chrismdp.com/2013/01/bdd-is-not-cucumber/
http://lizkeogh.com/2015/12/14/bdd-a-three-headed-monster/
https://www.toptal.com/freelance/your-boss-won-t-appreciate-tdd-try-bdd