15. 場景 (Scenario)
Scenario Outline: do simple operations
Given I enter <expression>
When I press "=" button
Then I get the answer <answer>
Examples:
| expression | answer |
| 3 + 2 | 5 |
| 3 - 2 | 1 |
| 3 * 2 | 6 |
| 3 / 2 | 1.5 |
| 3 +-*/ 2 | Invalid Input |
| hello world | Invalid Input |
16. 加法/乘法交換律
Scenario Outline: satisfy commutative property
When I enter <expression1> first
And I enter <expression2> again
Then I get the same answer
Examples:
| expression1 | expression2 |
| 3 + 4 | 4 + 3 |
| 2 * 5 | 5 * 2 |
17. 加法/乘法結合律
Scenario Outline: satisfy associative property
When I enter <expression1> first
And I enter <expression2> again
Then I get the same answer
Examples:
| expression1 | expression2 |
| (2 + 3) + 4 | 2 + (3 + 4) |
| 2 * (3 * 4) | (2 * 3) * 4 |
18. 乘法左/右分配律
Scenario Outline: satisfy distributive property
When I enter <expression1> first
And I enter <expression2> again
Then I get the same answer
Examples:
| expression1 | expression2 |
| 2 * (1 + 3) | (2*1) + (2*3) |
| (1 + 3) * 2 | (1*2) + (3*2) |
19. RD: 為什麼不測試這個?
Scenario Outline: parse an expression
Given I enter <expression>
When I press "=" button
Then I get an <array>
Examples:
| expression | array |
| 1+2 | ['1','+','2'] |
| 1*2 | ['1','*','2'] |
20. 關於測試
我說的其實是......
“Because designing the technical
solution is not the purpose of the
specification, you should focus
only on writing scenarios that
relate to the business rules.”
- Executable Specification with Scrum
22. 執⾏行測試
$ python manage.py behave --dry-run
…(略)
You can implement step definitions for undefined steps with these
snippets:
@given(u'I enter "3+2"')
def step_impl(context):
raise NotImplementedError(u'STEP: Given I enter "3+2"')
@when(u'I press "=" button')
def step_impl(context):
raise NotImplementedError(u'STEP: When I press "=" button')
@then(u'I get the answer "5"')
def step_impl(context):
raise NotImplementedError(u'STEP: Then I get the answer "5"')
23. 重構步驟
@given(u'I enter {expr}')
def step_impl(context, expr):
raise NotImplementedError(u'STEP: Given I enter {expr}')
@when(u'I press "=" button')
def step_impl(context):
raise NotImplementedError(u'STEP: When I press "="
button')
@then(u'I get the answer {answer}')
def step_impl(context, answer):
raise NotImplementedError(u'STEP: Then I get the answer
{answer}')
…(略)
複製貼上,修修改改
24. 執⾏行測試
$ python manage.py behave
Creating test database for alias 'default'...
Feature: Web calculator # features/calc.feature:3
As a student
In order to finish my homework
I want to do arithmatical operations
Scenario Outline: do simple operations -- @1.1
Given I enter 3 + 2
Traceback (most recent call last):
...(略)
NotImplementedError: STEP: Given I enter {expr}
When I press "=" button
Then I get the answer 5
溫馨提⽰示:還沒拿掉 NotImplementError
26. 執⾏行測試
$ python manage.py behave
Creating test database for alias 'default'...
Exception ImportError: No module named 'calc.calculator';
'calc' is not a package
Traceback (most recent call last):
...(略)
File "/home/vagrant/myWorkspace/demo/features/steps/
calc.py", line 1, in <module>
from calc.calculator import Calculator
ImportError: No module named 'calc.calculator'; 'calc' is not
a package
溫馨提⽰示:還沒實作 calc.calculator
28. 執⾏行測試
$ python manage.py behave
Creating test database for alias 'default'...
Feature: Web calculator # features/calc.feature:3
As a student
In order to finish my homework
I want to do arithmatical operations
Scenario Outline: do simple operations -- @1.1
Given I enter 3 + 2
When I press "=" button
Then I get the answer 5
Traceback (most recent call last):
...(略)
File "features/steps/calc.py", line 19, in step_impl
assert context.answer == answer
AssertionError
QA: 接下來就是 RD 的事了
36. 單元測試 (Unit Test)
from django.test import TestCase
from calc.calculator import Calculator
# Create your tests here.
class TestCalculator(TestCase):
def setUp(self):
self.calc = Calculator()
def test_evalString(self):
evalString = self.calc.evalString
self.assertEqual(evalString('0'), 0)
37. 執⾏行測試
$ python manage.py test -v2
test_evalString (calc.tests.TestCalculator) ... ok
--------------------------------------------------------------
Ran 1 test in 0.002s
OK
該提交程式碼與測試了
71. 執⾏行測試
$ python manage.py test -v2
...(略)
test_evalStack (calc.tests.TestCalculator) ... ok
test_evalString (calc.tests.TestCalculator) ... ok
test_invalid_input (calc.tests.TestCalculator) ... ok
test_parseString (calc.tests.TestCalculator) ... ok
--------------------------------------------------------------
Ran 4 tests in 0.007s
OK
$ git add .
$ git commit -m "parseString of '3+2': ok"
該提交程式碼與測試了
89. 執⾏行測試
$ python manage.py test
.....
--------------------------------------------------------------
Ran 5 tests in 0.012s
OK
$ git add .
$ git commit -m "DI and mock of SimpleCalculator"
該提交程式碼與測試了
95. 進⾏行實作
class Calculator:
def __init__(self, calc):
self.exprStack = []
def pushStack(s, l, t):
self.exprStack.append(t[0])
integer = Word(nums).addParseAction(pushStack)
addop = Literal('+') | Literal('-')
mulop = Literal('*') | Literal('/')
atom = integer
term = atom + ZeroOrMore((mulop + atom).addParseAction(pushStack))
expr = term + ZeroOrMore((addop + term).addParseAction(pushStack))
self.expr = expr + StringEnd()
...(略)
integer :: '0'...'9'*
addop :: '+' | '-'
mulop :: '*' | '/'
atom :: integer
term :: atom [mulop atom]*
expr :: term [addop term]*
96. 執⾏行測試
$ python manage.py test
......
--------------------------------------------------------------
Ran 6 tests in 0.018s
OK
$ git add .
$ git commit -m "evalString can handle the order of
operations"
該提交程式碼與測試了
111. 執⾏行測試
$ python manage.py test
..........
--------------------------------------------------------------
Ran 10 tests in 0.021s
OK
$ git add .
$ git commit -m "satisfy commutative, associative,
distributive properties"
該提交程式碼與測試了
112. 關於測試
我說的其實是......
“I get paid for code that works, not
for tests, so my philosophy is to
test as little as possible to reach a
given level of confidence.”
- Kent Beck’s answer to How deep are your unit tests?
114. 執⾏行測試
$ python manage.py behave
Creating test database for alias 'default'...
Feature: Web calculator # features/calc.feature:3
As a student
In order to finish my homework
I want to do arithmatical operations
Scenario Outline: do simple operations -- @1.1
Given I enter 3 + 2
When I press "=" button
Then I get the answer 5
…(略)
1 feature passed, 0 failed, 0 skipped
12 scenarios passed, 0 failed, 0 skipped
36 steps passed, 0 failed, 0 skipped, 0 undefined
133. DOC
Recap
User Stories
As a …, I want …, So that …
Scenarios
Given … When … Then …
Steps
@given(…)
def step_impl(context, …):
…
@when(…)
def step_impl(context, …):
…
@then(…)
def step_impl(context, …):
…
Interface
between the delegated tasks
and the domain model
Domain Models
Production code here…
Database Filesystem
Network
3rd party
library
Unit Tests
Test code here…
Test Double
Spy, Stub, Mock…
PM
PM
QA
RD
QA RD
Hardware
Remote
service