<bijan.parsia, christos.kotselidis@manchester.ac.uk>
(bug reports welcome!)
print("""1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
FizzBuzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
FizzBuzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
FizzBuzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz""")
for i in range(1,101):
if i % 3 == 0 and i % 5 == 0:
print('FizzBuzz')
elif i % 3 == 0:
print('Fizz')
elif i % 5 == 0:
print('Buzz')
else:
print(i)
i % 3 == 0
and i % 5 == 0
for i in range(1,101):
fizz = i % 3 == 0
buzz = i % 5 == 0
if fizz and buzz:
print('FizzBuzz')
elif fizz:
print('Fizz')
elif buzz:
print('Buzz')
else:
print(i)
_ % _ == 0
pattern!print
a lotFIZZ = 'Fizz'
BUZZ = 'Buzz'
def divisible_by(numerator, denominator):
return numerator % denominator == 0
def fizzit(num):
fizz = divisible_by(num, 3)
buzz = divisible_by(num, 5)
if fizz and buzz:
return FIZZ + BUZZ
elif fizz:
return FIZZ
elif buzz:
return BUZZ
else:
return i
for i in range(1,101):
print(fizzit(i))
FIZZ = 'Fizz'
BUZZ = 'Buzz'
"""We parameterise by:
* The range of integers covered.
* The text that is output.
* The multiples that trigger text to be output
https://www.tomdalling.com/blog/software-design/fizzbuzz-in-too-much-detail/"""
def fizzbuzz(bounds, triggers):
for i in bounds:
result = ''
for text, divisor in triggers:
result += text if i % divisor == 0 else ''
print(result if result else i)
fizzbuzz(range(1, 101), [
['Fizz', 3],
['Buzz', 5]])
def fizzbuzz(bounds, triggers):
for i in bounds:
result = ''
for text, predicate in triggers:
result += text if predicate(i) else ''
print(result if result else i)
fizzbuzz(range(1, 101), [
['Fizz', lambda i: i % 3 == 0],
['Buzz', lambda i: i % 5 == 0],
['Zazz', lambda i: i < 10]
])
This lecture was derived from the excellent blog post FizzBuzz In Too Much Detail by Tom Dalling.
Tom uses Ruby and goes a couple of steps further. Worth a read!
Implementation and design could be perfect, but if there was a spec misunderstanding, ambiguity, or change, the software will not be correct!
All these contribute to the user experience (UX)!
A defect in a software system is a quality level (for some quality) that is not acceptable.
What counts as a defect is often determined late in the game!
If your program crashes then it
If your program crashes, and the cause is in your code, then it
(Does QA hate you? — scroll for the cartoons as well as the wisdom.)
This is a logical, not temporal, order.
The penalty for failing to define the problem is that you can waste a lot of time solving the wrong problem. This is a double-barreled penalty because you also don't solve the right problem.
—McConnell, 3.3
We're going to look at your rainfalls before discussing it in detail.
We're going to do a code review!
You're going to work in 2-person teams!
To the lab! Material in the usual place.
The rainfall problem is still a challenge!
rainfall.py
?average_rainfall(input_list)
doctest
Design a program called rainfall that consumes a list of numbers representing daily rainfall amounts as entered by a user. The list may contain the number -999 indicating the end of the data of interest. Produce the average of the non-negative values in the list up to the first -999 (if it shows up). There may be negative numbers other than -999 in the list.
def average_rainfall(input_list):
""">>> average_rainfall(<<FIRST TEST INPUT>>)
<<FIRST EXPECTED RESULT>>
"""
# Here is where your code should go
return "Your computed average" #<-- change this!
$ python 1setup.py
Your computed average
$ python -m doctest 1setup.py
**********************************************************************
File "/Users/bparsia/Documents/2018/Teaching/COMP61511/labs/lab1/followup/1setup.py", line 2, in 1setup.average_rainfall
Failed example:
average_rainfall(<<FIRST TEST INPUT>>)
Exception raised:
Traceback (most recent call last):
File "//anaconda/lib/python3.5/doctest.py", line 1320, in __run
compileflags, 1), test.globs)
File "<doctest 1setup.average_rainfall[0]>", line 1
average_rainfall(<<FIRST TEST INPUT>>)
^
SyntaxError: invalid syntax
**********************************************************************
1 items had failures:
1 of 1 in 1setup.average_rainfall
***Test Failed*** 1 failures.
doctest
subprocess
etc.average_rainfall(input_list)
'2 3 4 67 -999'
==> [2, 3, 4, 67, -999]
average_rainfall
v 2def average_rainfall(input_list):
""">>> average_rainfall([2,3,4,67, -999])
19.0
"""
# Here is where your code should go
return "Your computed average" #<-- change this!
$ python 1setup.py
Your computed average
$ python -m doctest 2firstfull.py
**********************************************************************
File "/Users/bparsia/Documents/2018/Teaching/COMP61511/labs/lab1/followup/2firstfull.py", line 2, in 2firstfull.average_rainfall
Failed example:
average_rainfall([2,3,4,67, -999])
Expected:
19.0
Got:
'Your computed average'
**********************************************************************
1 items had failures:
1 of 1 in 2firstfull.average_rainfall
***Test Failed*** 1 failures.
def average_rainfall(input_list):
""">>> average_rainfall([2,3,4,67, -999])
19.0
"""
# Here is where your code should go
return sum(input_list)/len(input_list)
def average_rainfall(input_list):
""">>> average_rainfall([2,3,4,67, -999])
19.0
>>> average_rainfall([2,3,4,67])
19.0
"""
# Here is where your code should go
return sum(input_list)/len(input_list)
$ python -m doctest 4firstimpl2.py
**********************************************************************
File "/Users/bparsia/Documents/2018/Teaching/COMP61511/labs/lab1/followup/4firstimpl2.py", line 2, in 4firstimpl2.average_rainfall
Failed example:
average_rainfall([2,3,4,67, -999])
Expected:
19.0
Got:
-184.6
**********************************************************************
1 items had failures:
1 of 2 in 4firstimpl2.average_rainfall
***Test Failed*** 1 failures.
def average_rainfall(input_list):
""">>> average_rainfall([2,3,4,67, -999])
19.0
>>> average_rainfall([2,3,4,67])
19.0
"""
# Here is where your code should go
return sum(input_list[:-1])/len(input_list[:-1])
def average_rainfall(input_list):
""">>> average_rainfall([2, 3, 4, 67, -999])
19.0
>>> average_rainfall([2, 3, 4, 67])
19.0
"""
rainfall_sum = 0
count = 0
for i in input_list:
if i == -999:
break
else:
rainfall_sum += i
count += 1
# Here is where your code should go
return rainfall_sum/count
$ python -m doctest 5secondimpl.py
**********************************************************************
File "/Users/bparsia/Documents/2018/Teaching/COMP61511/labs/lab1/followup/5secondimpl.py", line 2, in 5secondimpl.average_rainfall
Failed example:
average_rainfall([2,3,4,67, -999])
Expected:
19.0
Got:
19.0
**********************************************************************
1 items had failures:
1 of 2 in 5secondimpl.average_rainfall
***Test Failed*** 1 failures.
Whaaaaaaaaaaaaaaaaaat?!
There was a bug in our tests
def average_rainfall(input_list):
""">>> average_rainfall([2, 3, 4, 67, -999])
19.0
vs.def average_rainfall(input_list):
""" >>> average_rainfall([2, 3, 4, 67])
19.0
Earlier tests failed for two reasons!
$ python -m doctest 6secondimpl2.py
$
$ python -m doctest -v 6secondimpl2.py
Trying:
average_rainfall([2,3,4,67, -999])
Expecting:
19.0
ok
Trying:
average_rainfall([2,3,4,67])
Expecting:
19.0
ok
1 items had no tests:
6secondimpl2
1 items passed all tests:
2 tests in 6secondimpl2.average_rainfall
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
[-999]
)[-999, 1]
the same as [-999]
?[]
and [-999]
?[-999]
and [-999, 0]
[-1, 0, 10, -999]
[-1, -2, -3, -999 1]
the same as []
?QA Engineer walks into a bar. Orders a beer. Orders 0 beers. Orders 999999999 beers. Orders a lizard. Orders -1 beers. Orders a sfdeljknesv.
— Bill Sempf (@sempf) September 23, 2014
McConnell: 22.2 Recommended Approach to Developer Testing
miniwc
from the specWhat were the challenges you encountered?
What challenges were inherent to the problem?
What challenges were environmental?
There seems to be a miniwc.py: 0.5/0.5 points.
There seems to be a doctest_miniwc.py and test files: 0.5/0.5 points.
Prohibited libraries have been used: 0/1 points. Formatting was correct: 1/1 points.
The script passed 35.7% of miniwc simple tests: 2/5 points.
The script passed 0.0% of miniwc binary tests: 0/1 points.
The script passed 0.0% of miniwc unicode tests: 0/1 points.
Penalties: none.
Total marks: 4.0/10.0
wc
miniwc.py
(now called wc.py
)