Skip to content

Commit dc44b93

Browse files
committed
deploy: da9112d
1 parent fa118ee commit dc44b93

18 files changed

Lines changed: 297 additions & 341 deletions

File tree

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+

_sources/exercises/unit_testing/unit_testing.rst.txt

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

_sources/index.rst.txt

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

_sources/modules/TestDrivenDevelopment.rst.txt

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

_sources/modules/Testing.rst.txt

Lines changed: 38 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,47 @@ This page is a quick overview of testing in Python. It provides some background
99

1010
Testing your code is an absolute necessity -- you need to have *some* way to know it's doing what it should.
1111

12+
Everyone tests their code -- that's how you know it works.
13+
14+
But when folks talk about "testing" -- what they really mean are automated tests.
15+
1216
Having your testing done in an automated way is really a good idea.
1317

14-
You've already seen a very basic testing strategy: putting some ``assert`` statements in the ``__name__ == "__main__"`` block.
1518

16-
You've written some tests using that strategy.
19+
What is testing?
20+
================
21+
22+
Code which runs your application in as close to a real environment as feasible and validates its behavior
23+
24+
25+
Terminology of testing
26+
----------------------
27+
28+
- Unit tests
29+
- Integration tests
30+
- High level system tests
31+
- Acceptance tests
32+
- Black box / White box testing
33+
34+
35+
"V" model and tests levels
36+
--------------------------
37+
.. image:: /_static/test_v_model.png
38+
39+
Note that "codeing" is at the bottom, and directly tied to unit-testing -- that's the place to start.
40+
41+
About Unit Testing
42+
------------------
1743

18-
These tests were pretty basic, and a bit awkward in places (testing error
19-
conditions in particular).
44+
0. Tests can be fully automated.
45+
1. Tests should be independent.
46+
2. Tests do not run in order, which shouldn't matter, see point 1.
47+
3. Test fixtures are available to do any setup / teardown needed for tests.
48+
4. Test behavior should not be implementation dependent.
49+
5. Mocking is available to fake stuff you may not want to run in your tests.
50+
51+
This all applies regardless of your test framework
2052

21-
.. centered:: **It gets better**
2253

2354
Test Frameworks
2455
---------------
@@ -49,108 +80,9 @@ It is a bit verbose: you have to write classes & methods (And we haven't covered
4980
But you will see it used in others' code, so it's good to be familiar with it.
5081
And seeing how verbose it can be will help you appreciate other options.
5182

52-
So here's a bit of an introduction -- if the class stuff confuses you, don't worry about it -- you don't need to actually DO this yourself at this point.
53-
54-
55-
Using ``unittest``
56-
------------------
57-
58-
To use ``unittest``, you need to write subclasses of the ``unittest.TestCase`` class (after importing the package, of course):
59-
60-
.. code-block:: python
61-
62-
# in test.py
63-
import unittest
64-
65-
class MyTests(unittest.TestCase):
66-
67-
def test_tautology(self):
68-
self.assertEqual(1, 1)
69-
70-
Then you run the tests by using the ``main`` function from the ``unittest``
71-
module:
72-
73-
.. code-block:: python
74-
75-
# in test.py
76-
if __name__ == '__main__':
77-
unittest.main()
78-
79-
``unittest.main()`` is called in the module where the tests are. Which means that they can be, but do not have to be, in the same file as your code.
80-
81-
NOTE: tests can also be run by "test runners" for more features.
82-
83-
84-
Testing Your Code
85-
-----------------
86-
87-
You can write your code in one file and test it from another -- and for all but the smallest projects, you want to do that.
88-
89-
in ``my_mod.py``:
90-
91-
.. code-block:: python
92-
93-
def my_func(val1, val2):
94-
return val1 * val2
95-
96-
in ``test_my_mod.py``:
97-
98-
.. code-block:: python
99-
100-
import unittest
101-
from my_mod import my_func
102-
103-
104-
class MyFuncTestCase(unittest.TestCase):
105-
def test_my_func(self):
106-
test_val1, test_val2 = 2, 3
107-
expected = 6
108-
actual = my_func(test_val1, test_val2)
109-
self.assertEqual(expected, actual)
110-
111-
if __name__ == '__main__':
112-
unittest.main()
113-
114-
So this is pretty straightforward, but it's kind of a lot of code for just one test, yes?
115-
116-
117-
Advantages of ``unittest``
118-
--------------------------
119-
120-
The ``unittest`` module is pretty full featured
121-
122-
It comes with the standard Python distribution, no installation required.
123-
124-
It provides a wide variety of assertions for testing many types of results.
125-
126-
It allows for a "set up" and "tear down" work flow both before and after all tests and before and after each test.
127-
128-
It's well known and well understood.
129-
130-
131-
Disadvantages of ``unittest``
132-
-----------------------------
133-
134-
It's Object Oriented, and quite "heavyweight".
135-
136-
- modeled after Java's ``JUnit``.
137-
138-
It uses the Framework design pattern, so knowing how to use the features means learning what to override.
139-
140-
Needing to override means you have to be cautious.
141-
142-
Test discovery is both inflexible and brittle.
143-
144-
It doesn't really take advantage of Python's introspection capabilities:
145-
- There are explicit "assert" methods for each type of test
146-
- The available assertions are not the least bit complete
147-
- All the assertions really do is provide pretty printing of errors
148-
149-
Testing for Exceptions is awkward
150-
151-
Test discovery is limited
83+
See :ref:`advanced_testing` for more on that.
15284

153-
And there is no built-in parameterized testing.
85+
For now -- we'regoingto us pytest -- far simpler to get started, and advanced enough for the largest, most complex projects.
15486

15587

15688
Other Options

0 commit comments

Comments
 (0)