Skip to content

Commit da9112d

Browse files
updated the testing page(s) added a new example.
1 parent f2c59a8 commit da9112d

8 files changed

Lines changed: 284 additions & 165 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""
2+
3+
Test driven development:
4+
5+
6+
Example from Coding Bat: List-2 > sum13
7+
8+
https://codingbat.com/prob/p167025
9+
10+
Return the sum of the numbers in the array, returning 0 for an empty array. Except the number 13 is very unlucky, so it does not count and numbers that come immediately after a 13 also do not count.
11+
12+
13+
sum13([1, 2, 2, 1]) → 6
14+
sum13([1, 1]) → 2
15+
sum13([1, 2, 2, 1, 13]) → 6
16+
sum13([1, 2, 2, 1]) → 6
17+
sum13([1, 1]) → 2
18+
sum13([1, 2, 2, 1, 13]) → 6
19+
sum13([1, 2, 13, 2, 1, 13]) → 4
20+
sum13([13, 1, 2, 13, 2, 1, 13]) → 3
21+
sum13([]) → 0
22+
sum13([13]) → 0
23+
sum13([13, 13]) → 0
24+
sum13([13, 0, 13]) → 0
25+
sum13([13, 1, 13]) → 0
26+
sum13([5, 7, 2]) → 14
27+
sum13([5, 13, 2]) → 5
28+
sum13([0]) → 0
29+
sum13([13, 0]) → 0
30+
"""
31+
32+
import pytest
33+
34+
def sum13(nums):
35+
"""
36+
non-functional -- but the tests will run (and fail)
37+
"""
38+
return None
39+
40+
# def sum13(nums):
41+
# """
42+
# simple sum -- no special handling of 13 -- should pass some tests.
43+
# """
44+
# return sum(nums)
45+
46+
# def sum13(nums):
47+
# """
48+
# using a comprehension to filter out the 13s
49+
50+
# - more tests should pass, but not all.
51+
# """
52+
# return sum(n for n in nums if n!=13)
53+
54+
55+
# def sum13(nums):
56+
# """
57+
# darn -- comprehension can't handle the "after a 13" case
58+
59+
# do it from scratch with while loop
60+
61+
# fails the two 13s in a row test!
62+
# """
63+
# total = 0
64+
# i = 0
65+
# while i < len(nums):
66+
# if nums[i] != 13:
67+
# total += nums[i]
68+
# else:
69+
# i += 1
70+
# i += 1
71+
# return total
72+
73+
74+
# def sum13(nums):
75+
# """
76+
# Use a for loop, and keep track of the previous 13
77+
78+
# passes all tests!
79+
# """
80+
# print(nums)
81+
# total = 0
82+
# prev_13 = False
83+
# for i, n in enumerate(nums):
84+
# if n == 13:
85+
# prev_13 = True
86+
# continue
87+
# elif prev_13:
88+
# prev_13 = False
89+
# continue
90+
# else:
91+
# total += n
92+
# return total
93+
94+
95+
# def sum13(nums):
96+
# """
97+
# Use the iterator protocol -- nifty? but not any simpler really.
98+
99+
# Fails for repeated 13 in middle
100+
101+
# Works with any iterable, so that's nice.
102+
# """
103+
# total = 0
104+
# nums_i = iter(nums)
105+
# for n in nums_i:
106+
# if n != 13:
107+
# total += n
108+
# else:
109+
# try:
110+
# next(nums_i)
111+
# # this is necessary for the case where there's a 13 at the end.
112+
# except StopIteration:
113+
# break
114+
# return total
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""
2+
3+
Test driven development:
4+
5+
Example from Coding Bat: List-2 > sum13
6+
7+
https://codingbat.com/prob/p167025
8+
9+
Return the sum of the numbers in the array, returning 0 for an empty array. Except the number 13 is very unlucky, so it does not count and numbers that come immediately after a 13 also do not count.
10+
11+
12+
The tests that are used on codingbat:
13+
14+
sum13([1, 2, 2, 1]) → 6
15+
sum13([1, 1]) → 2
16+
sum13([1, 2, 2, 1, 13]) → 6
17+
sum13([1, 2, 2, 1]) → 6
18+
sum13([1, 1]) → 2
19+
sum13([1, 2, 2, 1, 13]) → 6
20+
sum13([1, 2, 13, 2, 1, 13]) → 4
21+
sum13([13, 1, 2, 13, 2, 1, 13]) → 3
22+
sum13([]) → 0
23+
sum13([13]) → 0
24+
sum13([13, 13]) → 0
25+
sum13([13, 0, 13]) → 0
26+
sum13([13, 1, 13]) → 0
27+
sum13([5, 7, 2]) → 14
28+
sum13([5, 13, 2]) → 5
29+
sum13([0]) → 0
30+
sum13([13, 0]) → 0
31+
"""
32+
33+
import pytest
34+
35+
from sum_13 import sum13
36+
37+
38+
# Using the nifty pytest.parametrize, so we only have to write one test
39+
40+
test_data = [
41+
([1, 2, 2, 1], 6),
42+
([1, 1], 2),
43+
([1, 2, 2, 1, 13], 6),
44+
([1, 2, 2, 1], 6),
45+
([1, 1], 2),
46+
([1, 2, 2, 1, 13], 6),
47+
([1, 2, 13, 2, 1, 13], 4),
48+
([13, 1, 2, 13, 2, 1, 13], 3),
49+
([], 0),
50+
([13], 0),
51+
([13, 13], 0),
52+
([13, 0, 13], 0),
53+
([13, 1, 13], 0),
54+
([5, 7, 2], 14),
55+
([5, 13, 2], 5),
56+
([0], 0),
57+
([13, 0], 0),
58+
# These are not part of original test suite
59+
# uncomment them, and see if your solution still passes.
60+
# ([3, 13, 13, 2, 5], 8),
61+
# (iter([13, 1, 2, 13, 2, 1, 13]), 3), # Does it work with an iterable?
62+
]
63+
64+
@pytest.mark.parametrize('nums, result', test_data)
65+
def test_sum13(nums, result):
66+
assert sum13(nums) == result
67+
68+
69+
70+

source/exercises/unit_testing/unit_testing.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ Now edit the function in ``walnut_party.py``, and each time you make a change, r
9292

9393
When the tests pass -- you are done! That's the beauty of test-driven development.
9494

95+
Another Example:
96+
----------------
97+
98+
Here's another example from the codingbat site:
99+
100+
:download:`test_sum_13.py <test_sum_13.py>`
101+
102+
103+
104+
105+
106+
95107
Doing your own:
96108
---------------
97109

source/index.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
Programming in Python
88
#####################
99

10-
This site holds many of the materials for the
10+
This site holds a set of materials for an introductory course in Python.
11+
12+
THe course was originally developed by a wide variety of instructors for the
1113
`University of Washington Professional and Continuing Education Python Certificate <https://www.pce.uw.edu/certificates/python-programming>`_
1214
`Introductory class <https://www.pce.uw.edu/courses/programming-in-python>`_
1315

14-
This site can be thought of as the textbook for Programming in Python: the first course in the program. It contains notes about the topics covered in the classes, programming exercises, supplemental materials about setting up a development environment, and assorted references about Python-related topics.
16+
This site can be thought of as the textbook for an introduction to programming in Python:
17+
It contains notes about the topics covered in the classes, programming exercises, supplemental materials about setting up a development environment, and assorted references about Python-related topics.
1518

1619
Many of these topics can be useful on their own, but each assumes that you know concepts that were introduced earlier in the program, so working through them in order can be helpful.
1720

@@ -35,7 +38,7 @@ They are built with the Sphinx documentation system, utilizing Restructured Text
3538

3639
It is managed in this gitHub repository:
3740

38-
https://github.com/UWPCE-PythonCert/ProgrammingInPython
41+
https://github.com/PythonCHB/ProgrammingInPython
3942

4043
Readers are encouraged to report omissions, typos, or make suggestions for improvements via issues and pull requests on that repository.
4144

@@ -45,7 +48,7 @@ Example Code
4548

4649
Assorted Example code can be found in the source repository for these documents. Most of the examples are linked to directly from these documents, but it might be helpful to have them all in one place:
4750

48-
https://github.com/UWPCE-PythonCert/ProgrammingInPython/tree/master/source/examples
51+
https://github.com/PythonCHB/ProgrammingInPython/tree/main/source/examples
4952

5053

5154
.. Indices and tables

source/modules/TestDrivenDevelopment.rst

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11

22
.. _test_driven_development:
33

4-
FIXME: change the path from my personal to something generic
5-
64
#######################
75
Test Driven Development
86
#######################
@@ -16,7 +14,7 @@ Test Driven Development
1614
"Test Driven Development" (TDD) is a development strategy that integrates the development of unit tests with the code itself. In particular, you write the tests *before* you write the code, which seems pretty backward, but it has some real strengths.
1715

1816
We'll demonstrate this technique with an example.
19-
 
17+
2018
The following is adapted from Mark Pilgrim's excellent "Dive into Python":
2119

2220
https://diveintopython3.problemsolving.io/
@@ -105,7 +103,7 @@ want it to. You read that right: you’re going to write code that tests
105103
code that you haven’t written yet.
106104

107105
This is called *test-driven development*, or TDD. The set of two
108-
conversion functions — ``to_roman()``, and later ``from_roman()`` — can
106+
conversion functions``to_roman()``, and later ``from_roman()``can
109107
be written and tested as a unit, separate from any larger program that
110108
uses them.
111109

@@ -115,9 +113,7 @@ Technically, you can write unit tests with plain Python -- recall the ``assert``
115113

116114
$ python -m pip install pytest
117115

118-
Once installed, you should have the pytest command available in your terminal.
119-
120-
FIXME: Maybe add a small page on installing and using pytest?
116+
Once installed, you should have the pytest command available in your terminal.
121117

122118
Unit testing is an important part of an overall testing-centric
123119
development strategy. If you write unit tests, it is important to write
@@ -262,7 +258,7 @@ You don’t need to test every possible input, but you should try to test all th
262258

263259
.. note:: This is a major challenge of unit testing -- how to catch all the edge cases, without over testing every little thing.
264260

265-
`pytest` makes it really simple to write a test case: simply define a function named ``test_anything``. pytest will identify any function with: "``test_``"" at the start of the name as a test function.
261+
`pytest` makes it really simple to write a test case: simply define a function named ``test_anything``. pytest will identify any function with: "``test_``" at the start of the name as a test function.
266262

267263
* Every individual test is its own function. A test function takes no parameters, returns no value, and must have a name beginning with the five letters ``test_``.
268264
If a test function exits normally without a failing assertion or other exception, the test is considered passed; if the function raises a failed assertion, failed.
@@ -604,7 +600,7 @@ sort of failure; they must fail in the way you expect.
604600
In [13]: to_roman(9000)
605601
Out[13]: 'MMMMMMMMM'
606602
607-
That’s definitely *not* what you wanted — that’s not even a valid Roman
603+
That’s definitely *not* what you wantedthat’s not even a valid Roman
608604
numeral!
609605
In fact, after 3000, each of these numbers is outside the range of
610606
acceptable input, but the function returns a bogus value anyway.
@@ -684,7 +680,7 @@ code to pass it yet. Did it fail in the way you expected?
684680
Yes! ``pytest.raises`` did its job -- a ``ValueError`` was not raised, and the test failed.
685681

686682
Of course, the ``to_roman()`` function isn’t raising the ``ValueError`` because you haven’t told it to do that yet.
687-
That’s excellent news! It means this is a valid test case — it fails before you write the code to make it pass.
683+
That’s excellent news! It means this is a valid test caseit fails before you write the code to make it pass.
688684

689685
Now you can write the code to make this test pass.
690686

0 commit comments

Comments
 (0)