telephone
Part of `Computer Programming`_ is sending input data to a process and getting output data back
input_data -> process -> output_data
I send things (input data) to a program_ to test it, and check if what I think will happen (my expectation) is the same as the results I get (reality). This helps me answer two questions:
what is the same?
what is different?
The difference helps me know what to change to get what I want. I do this with the assertEqual method, which takes 2 inputs and checks if they are the same
self.assertEqual(reality, my_expectation)
where
realityis what happens when I do something with codemy_expectationis what I think will happen when I do something with code
The exercises in this chapter show how I can pass input data from a test to a function in a module.
preview
I have these tests by the end of the chapter
start the project
I name this project
telephoneI open a terminal_
I use uv_ to make a directory_ for the project and initialize it
uv init telephonethe terminal_ shows
Initialized project `telephone` at `.../pumping_python/telephone`then goes back to the command line.
I change directory_ to the project
cd telephonethe terminal_ shows I am in the
telephonefolder_.../pumping_python/telephoneI make a directory_ for the source code
mkdir srcthe terminal_ goes back to the command line.
I use the `mv program`_ to change the name of
main.pytotelephone.pyand move it to thesrcfolder_mv main.py src/telephone.pyMove-Item main.py src/telephone.pythe terminal_ goes back to the command line.
I `make a directory`_ for the tests
mkdir teststhe terminal_ goes back to the command line.
I make the
testsdirectory_ a `Python package`_Danger
use 2 underscores (__) before and after
initfor__init__.pynot_init_.pytouch tests/__init__.pyNew-Item tests/__init__.pythe terminal_ goes back to the command line.
I make a Python file for the tests in the
testsdirectory_touch tests/test_telephone.pyNew-Item tests/test_telephone.pythe terminal_ goes back to the command line.
I open
test_telephone.pyin the editor of the `Integrated Development Environment (IDE)`_Tip
I can open a file_ from the terminal_ in the `Integrated Development Environment (IDE)`_ with the name of the program_ and the name of the file_. That means if I type this in the terminal_
code tests/test_telephone.py`Visual Studio Code`_ opens
test_telephone.pyin the editorI add the first failing test to
test_telephone.py1import unittest 2 3 4class TestTelephone(unittest.TestCase): 5 6 def test_failure(self): 7 self.assertFalse(True)I go back to the terminal_ to make a requirements file_ for the `Python packages`_ I need
echo "pytest" > requirements.txtthe terminal_ goes back to the command line.
I add `pytest-watcher`_ to the requirements file_
echo "pytest-watcher" >> requirements.txtthe terminal_ goes back to the command line.
I install the `Python packages`_ that I wrote in the requirements file_
uv add --requirement requirements.txtthe terminal_ shows that it installed the `Python packages`_
I add the new files_ and folders_ to git_ for tracking
git add .the terminal_ goes back to the command line.
I add a git_ commit message
git commit --all --message 'setup project'the terminal_ shows
[main (root-commit) a0b12c3] setup project 9 files changed, 148 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 src/telephone.py create mode 100644 tests/__init__.py create mode 100644 tests/test_telephone.py create mode 100644 uv.lockthen goes back to the command line.
I use `pytest-watcher`_ to run the tests automatically
uv run pytest-watcher . --nowthe terminal_ is my friend, and shows AssertionError
================================ FAILURES ================================ ______________________ TestTelephone.test_failure ________________________ self = <tests.test_telephone.TestTelephone testMethod=test_failure> def test_failure(self): > self.assertFalse(True) E AssertionError: True is not false tests/test_telephone.py:7: AssertionError ======================== short test summary info ========================= FAILED tests/test_telephone.py::TestTelephone::test_failure - AssertionError: True is not false =========================== 1 failed in X.YZs ============================if the terminal_ does not show the same error, then check
if your
tests/__init__.pyhas two underscores (__) before and afterinitfor__init__.pynot_init_.pyif you ran
echo "pytest-watcher" >> requirements.txt, to addpytest-watcherto the requirements file_
fix those errors and try to run
uv run pytest-watcher . --nowagainI add AssertionError to the list of Exceptions seen in
test_telephone.pyin the editor4class TestTelephone(unittest.TestCase): 5 6 def test_failure(self): 7 self.assertFalse(True) 8 9 10# Exceptions seen 11# AssertionErrorthen I change True to False in the assertion
7 self.assertFalse(False)the test passes.
test_passing_a_string
I can pass a string_ from a test to a function
RED: make it fail
I change test_failure to test_passing_a_string
4class TestTelephone(unittest.TestCase):
5
6 def test_passing_a_string(self):
7 reality = src.telephone.text('hello')
8 my_expectation = 'I got: hello'
9 self.assertEqual(reality, my_expectation)
10
11
12# Exceptions seen
13# AssertionError
the terminal_ is my friend, and shows NameError
NameError: name 'src' is not defined
because there is no definition for src in test_telephone.py
GREEN: make it pass
I add NameError to the list of Exceptions seen
12# Exceptions seen 13# AssertionError 14# NameErrorI add an `import statement`_ for the
telephonemodule from thesrcfolder_, at the top of the file_1import src.telephone 2import unittest 3 4 5class TestTelephone(unittest.TestCase):import src.telephonebrings in an object (everything in Python is an object) that represents thetelephone.pymodule from thesrcfolder_ so I can use it intest_telephone.pythe terminal_ is my friend, and shows AttributeError
AttributeError: module 'src.telephone' has no attribute 'text'because there is no definition for
textintelephone.pyin thesrcfolder_
I add AttributeError to the list of Exceptions seen in
test_telephone.py13# Exceptions seen 14# AssertionError 15# NameError 16# AttributeErrorI use the Explorer to open
telephone.pyfrom thesrcfolder in the editorI delete the text, then add a name to
telephone.py1textthe terminal_ is my friend, and shows NameError
NameError: name 'text' is not definedbecause the name is in the file_, and I have not told Python_ what it means
I point
textto None1# text 2text = Nonethe terminal_ is my friend, and shows TypeError
TypeError: 'NoneType' object is not callableI add TypeError to the list of Exceptions seen in
test_telephone.py13# Exceptions seen 14# AssertionError 15# NameError 16# AttributeError 17# TypeErrorI change
textto a function intelephone.pyto make it callable_1# text 2# text = None 3def text(): 4 return Nonethe terminal_ is my friend, and shows TypeError
TypeError: text() takes 0 positional arguments but 1 was givenbecause the definition for
src.telephone.textdoes not allow calling it with inputs and the test sends'hello'as input (the parentheses are empty).I make the function take input
1# text 2# text = None 3# def text(): 4def text(the_input): 5 return Nonethe_inputis the name I used for the input, I can use any name I want.the terminal_ is my friend, and shows AssertionError
AssertionError: None != 'I got: hello'because the assertion expects
'I got: hello'and thetextfunction returns None.
I copy the string_ from the terminal_ and paste it in the `return statement`_ to replace None
1# text 2# text = None 3# def text(): 4def text(the_input): 5 # return None 6 return 'I got: hello'the test passes!
REFACTOR: make it better
The problem with this solution is that the text function does not care about what it gets, it always returns 'I got: hello' when called. I want it to return the value it gets as part of the message.
I add a new assertion to
test_passing_a_stringintest_telephone.py7 def test_passing_a_string(self): 8 reality = src.telephone.text('hello') 9 my_expectation = 'I got: hello' 10 self.assertEqual(reality, my_expectation) 11 12 reality = src.telephone.text('yes') 13 my_expectation = 'I got: yes' 14 self.assertEqual(reality, my_expectation) 15 16 17# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: hello' != 'I got: yes'because the
textfunction always returns'I got: hello'and this assertion expects'I got: yes'I change the `return statement`_ in
telephone.pyto match1# text 2# text = None 3# def text(): 4def text(the_input): 5 # return None 6 # return 'I got: hello' 7 return 'I got: yes'the terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: yes' != 'I got: hello'it did not work, my change broke the assertion that was passing before. The `return statement`_ has to use the input it gets as part of the output.
what is string interpolation?
I use an f-string which lets me add any variables I want to a string_
1# text 2# text = None 3# def text(): 4def text(the_input): 5 # return None 6 # return 'I got: hello' 7 # return 'I got: yes' 8 return f'I got: {the_input}'the test passes.
I remove the commented lines
1def text(the_input): 2 return f'I got: {the_input}'This is called string interpolation, I can use it to put values in strings_. A string_ is anything inside quotes e.g.
'single quotes''''triple single quotes'''"double quotes""""triple double quotes"""
I add a variable to use the remove repetition of
'hello'from the test intest_telephone.py7 def test_passing_a_string(self): 8 a_string = 'hello' 9 reality = src.telephone.text('hello') 10 my_expectation = 'I got: hello' 11 self.assertEqual(reality, my_expectation)I use the new variable and string interpolation to remove repetition of
'hello'from the test7 def test_passing_a_string(self): 8 a_string = 'hello' 9 # reality = src.telephone.text('hello') 10 reality = src.telephone.text(a_string) 11 # my_expectation = 'I got: hello' 12 my_expectation = f'I got: {a_string}' 13 self.assertEqual(reality, my_expectation)the test is still green.
I add a variable to use to remove repetition of
'yes'from the test7 def test_passing_a_string(self): 8 a_string = 'hello' 9 # reality = src.telephone.text('hello') 10 reality = src.telephone.text(a_string) 11 # my_expectation = 'I got: hello' 12 my_expectation = f'I got: {a_string}' 13 self.assertEqual(reality, my_expectation) 14 15 a_string = 'yes' 16 reality = src.telephone.text('yes') 17 my_expectation = 'I got: yes' 18 self.assertEqual(reality, my_expectation)I use the new variable and string interpolation to remove repetition of
'yes'from the test15 a_string = 'yes' 16 # reality = src.telephone.text('yes') 17 reality = src.telephone.text(a_string) 18 # my_expectation = 'I got: yes' 19 my_expectation = f'I got: {a_string}' 20 self.assertEqual(reality, my_expectation) 21 22 23# Exceptions seenstill green.
I remove the commented lines
7 def test_passing_a_string(self): 8 a_string = 'hello' 9 reality = src.telephone.text(a_string) 10 my_expectation = f'I got: {a_string}' 11 self.assertEqual(reality, my_expectation) 12 13 a_string = 'yes' 14 reality = src.telephone.text(a_string) 15 my_expectation = f'I got: {a_string}' 16 self.assertEqual(reality, my_expectation) 17 18 19# Exceptions seenI open a new terminal_ then change directories to
telephonecd telephonethe terminal_ shows I am in the
telephonefolder_.../pumping_python/telephoneI add a git_ commit message in the new terminal_
git commit -am 'add test_passing_a_string'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_none
I can pass None from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a failing test for None (the simplest Python data structure) to
test_telephone.py7 def test_passing_a_string(self): 8 a_string = 'hello' 9 reality = src.telephone.text(a_string) 10 my_expectation = f'I got: {a_string}' 11 self.assertEqual(reality, my_expectation) 12 13 a_string = 'yes' 14 reality = src.telephone.text(a_string) 15 my_expectation = f'I got: {a_string}' 16 self.assertEqual(reality, my_expectation) 17 18 def test_passing_none(self): 19 reality = src.telephone.text(None) 20 my_expectation = 'I got: "None"' 21 self.assertEqual(reality, my_expectation) 22 23 24# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: None' != "I got: 'None'"
GREEN: make it pass
I remove the quotes around None in my_expectation
18 def test_passing_none(self):
19 reality = src.telephone.text(None)
20 # my_expectation = 'I got: "None"'
21 my_expectation = 'I got: None'
22 self.assertEqual(reality, my_expectation)
23
24
25# Exceptions seen
the test passes.
REFACTOR: make it better
I remove the comments
18 def test_passing_none(self): 19 reality = src.telephone.text(None) 20 my_expectation = 'I got: None' 21 self.assertEqual(reality, my_expectation) 22 23 24# Exceptions seenI add a git_ commit message in the other terminal_
git commit --all --message 'add test_passing_none'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_booleans
I can pass booleans from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a test for booleans, first with an assertion for False
18 def test_passing_none(self): 19 reality = src.telephone.text(None) 20 my_expectation = 'I got: None' 21 self.assertEqual(reality, my_expectation) 22 23 def test_passing_booleans(self): 24 reality = src.telephone.text(False) 25 my_expectation = 'I got: "False"' 26 self.assertEqual(reality, my_expectation) 27 28 29# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: False' != 'I got: "False"'
GREEN: make it pass
I remove the quotes around False in my_expectation
23 def test_passing_booleans(self):
24 reality = src.telephone.text(False)
25 # my_expectation = 'I got: "False"'
26 my_expectation = 'I got: False'
27 self.assertEqual(reality, my_expectation)
28
29
30# Exceptions seen
the test passes.
REFACTOR: make it better
-
23 def test_passing_booleans(self): 24 reality = src.telephone.text(False) 25 my_expectation = 'I got: False' 26 self.assertEqual(reality, my_expectation) 27 28 reality = src.telephone.text(True) 29 my_expectation = 'I got: "True"' 30 self.assertEqual(reality, my_expectation) 31 32 33# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: True' != 'I got: "True"' I remove the quotes around True in
my_expectation29 reality = src.telephone.text(True) 30 # my_expectation = 'I got: "True"' 31 my_expectation = 'I got: True' 32 self.assertEqual(reality, my_expectation) 33 34 35# Exceptions seenthe test passes.
I remove the comments
23 def test_passing_booleans(self): 24 reality = src.telephone.text(False) 25 my_expectation = 'I got: False' 26 self.assertEqual(reality, my_expectation) 27 28 reality = src.telephone.text(True) 29 my_expectation = 'I got: True' 30 self.assertEqual(reality, my_expectation) 31 32 33# Exceptions seenI add a git_ commit message in the other terminal_
git commit -am 'add test_passing_booleans'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_an_integer
I can pass an integer_ (a whole number without decimals) from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a test for an integer_
28 reality = src.telephone.text(True) 29 my_expectation = 'I got: True' 30 self.assertEqual(reality, my_expectation) 31 32 def test_passing_an_integer(self): 33 reality = src.telephone.text(1234) 34 my_expectation = 'I got: "1234"' 35 self.assertEqual(reality, my_expectation) 36 37 38# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: 1234' != "I got: '1234'"
GREEN: make it pass
I remove the quotes around the integer_ in my_expectation
32 def test_passing_an_integer(self):
33 reality = src.telephone.text(1234)
34 # my_expectation = 'I got: "1234"'
35 my_expectation = 'I got: 1234'
36 self.assertEqual(reality, my_expectation)
37
38
39# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of
123432 def test_passing_an_integer(self): 33 an_integer = 1234 34 reality = src.telephone.text(1234) 35 # my_expectation = 'I got: "1234"' 36 my_expectation = 'I got: 1234' 37 self.assertEqual(reality, my_expectation) 38 39 40# Exceptions seenI use the variable with string interpolation to remove repetition of
123432 def test_passing_an_integer(self): 33 an_integer = 1234 34 # reality = src.telephone.text(1234) 35 reality = src.telephone.text(an_integer) 36 # my_expectation = 'I got: "1234"' 37 # my_expectation = 'I got: 1234' 38 my_expectation = f'I got: {an_integer}' 39 self.assertEqual(reality, my_expectation) 40 41 42# Exceptions seenthe test is still green.
I remove the comments
32 def test_passing_an_integer(self): 33 an_integer = 1234 34 reality = src.telephone.text(an_integer) 35 my_expectation = f'I got: {an_integer}' 36 self.assertEqual(reality, my_expectation) 37 38 39# Exceptions seenI add a git_ commit message in the other terminal_
git commit --all --message \ 'add test_passing_an_integer'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_a_float
I can pass a float_ (binary floating point decimal number) from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a test for a float_ (binary floating point decimal numbers)
32 def test_passing_an_integer(self): 33 an_integer = 1234 34 reality = src.telephone.text(an_integer) 35 my_expectation = f'I got: {an_integer}' 36 self.assertEqual(reality, my_expectation) 37 38 def test_passing_a_float(self): 39 reality = src.telephone.text(1.234) 40 my_expectation = 'I got: "1.234"' 41 self.assertEqual(reality, my_expectation) 42 43 44# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: 1.234' != 'I got: "1.234"'
GREEN: make it pass
I remove the quotes around the float_ in my_expectation
38 def test_passing_a_float(self):
39 reality = src.telephone.text(1.234)
40 # my_expectation = 'I got: "1.234"'
41 my_expectation = 'I got: 1.234'
42 self.assertEqual(reality, my_expectation)
43
44
45# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of
1.23438 def test_passing_a_float(self): 39 a_float = 1.234 40 reality = src.telephone.text(1.234) 41 # my_expectation = 'I got: "1.234"' 42 my_expectation = 'I got: 1.234' 43 self.assertEqual(reality, my_expectation) 44 45 46# Exceptions seenI use the variable with an f-string to remove repetition of
1.23438 def test_passing_a_float(self): 39 a_float = 1.234 40 # reality = src.telephone.text(1.234) 41 reality = src.telephone.text(a_float) 42 # my_expectation = 'I got: "1.234"' 43 # my_expectation = 'I got: 1.234' 44 my_expectation = f'I got: {a_float}' 45 self.assertEqual(reality, my_expectation) 46 47 48# Exceptions seenthe test is still green.
I remove the comments
38 def test_passing_a_float(self): 39 a_float = 1.234 40 reality = src.telephone.text(a_float) 41 my_expectation = f'I got: {a_float}' 42 self.assertEqual(reality, my_expectation) 43 44 45# Exceptions seenI add a git_ commit message in the other terminal_
git commit -am 'add test_passing_a_float'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_a_tuple
I can pass a tuple_ (anything in parentheses ( ) separated by a comma) from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a test for a tuple_
38 def test_passing_a_float(self): 39 a_float = 1.234 40 reality = src.telephone.text(a_float) 41 my_expectation = f'I got: {a_float}' 42 self.assertEqual(reality, my_expectation) 43 44 def test_passing_a_tuple(self): 45 reality = src.telephone.text((1, 2, 3, 'n')) 46 my_expectation = 'I got: (1, 2, 3, n)' 47 self.assertEqual(reality, my_expectation) 48 49 50# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: (1, 2, 3, 'n')" != 'I got: "(1, 2, 3, n)"'
GREEN: make it pass
I change the tuple_ in my_expectation to match reality
44 def test_passing_a_tuple(self):
45 reality = src.telephone.text((1, 2, 3, 'n'))
46 # my_expectation = 'I got: (1, 2, 3, n)'
47 my_expectation = "I got: (1, 2, 3, 'n')"
48 self.assertEqual(reality, my_expectation)
49
50
51# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of the tuple_
44 def test_passing_a_tuple(self): 45 a_tuple = (1, 2, 3, 'n') 46 reality = src.telephone.text((1, 2, 3, 'n')) 47 # my_expectation = 'I got: (1, 2, 3, n)' 48 my_expectation = "I got: (1, 2, 3, 'n')" 49 self.assertEqual(reality, my_expectation) 50 51 52# Exceptions seenI use the variable with string interpolation to remove repetition of the tuple_
44 def test_passing_a_tuple(self): 45 a_tuple = (1, 2, 3, 'n') 46 # reality = src.telephone.text((1, 2, 3, 'n')) 47 reality = src.telephone.text(a_tuple) 48 # my_expectation = 'I got: (1, 2, 3, n)' 49 # my_expectation = "I got: (1, 2, 3, 'n')" 50 my_expectation = f"I got: {a_tuple}" 51 self.assertEqual(reality, my_expectation) 52 53 54# Exceptions seenthe test is still green.
I remove the comments
44 def test_passing_a_tuple(self): 45 a_tuple = (1, 2, 3, 'n') 46 reality = src.telephone.text(a_tuple) 47 my_expectation = f"I got: {a_tuple}" 48 self.assertEqual(reality, my_expectation) 49 50 51# Exceptions seenI add a git_ commit message in the other terminal_
git commit --all --message 'add test_passing_a_tuple'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_a_list
I can pass a list (anything in square brackets [ ]) from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a test for a list
44 def test_passing_a_tuple(self): 45 a_tuple = (1, 2, 3, 'n') 46 reality = src.telephone.text(a_tuple) 47 my_expectation = f"I got: {a_tuple}" 48 self.assertEqual(reality, my_expectation) 49 50 def test_passing_a_list(self): 51 reality = src.telephone.text([1, 2, 3, 'n']) 52 my_expectation = 'I got: [1, 2, 3, "n"]' 53 self.assertEqual(reality, my_expectation) 54 55 56# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: [1, 2, 3, 'n']" != "I got: '[1, 2, 3, n]'"
GREEN: make it pass
I change the list in my_expectation to match reality
50 def test_passing_a_list(self):
51 reality = src.telephone.text([1, 2, 3, 'n'])
52 # my_expectation = 'I got: [1, 2, 3, "n"]'
53 my_expectation = "I got: [1, 2, 3, 'n']"
54 self.assertEqual(reality, my_expectation)
55
56
57# Exceptions seen
the test passes. Python_ changed the double quotes (") in the list to a single quote (').
REFACTOR: make it better
I add a variable to use to remove repetition of the list
50 def test_passing_a_list(self): 51 a_list = [1, 2, 3, 'n'] 52 reality = src.telephone.text([1, 2, 3, 'n']) 53 # my_expectation = 'I got: [1, 2, 3, "n"]' 54 my_expectation = "I got: [1, 2, 3, 'n']" 55 self.assertEqual(reality, my_expectation) 56 57 58# Exceptions seenI use the variable with an f-string to remove repetition of the list
50 def test_passing_a_list(self): 51 a_list = [1, 2, 3, 'n'] 52 # reality = src.telephone.text([1, 2, 3, 'n']) 53 reality = src.telephone.text(a_list) 54 # my_expectation = 'I got: [1, 2, 3, "n"]' 55 # my_expectation = "I got: [1, 2, 3, 'n']" 56 my_expectation = f"I got: {a_list}" 57 self.assertEqual(reality, my_expectation) 58 59 60# Exceptions seenthe test is still green.
I remove the comments
50 def test_passing_a_list(self): 51 a_list = [1, 2, 3, 'n'] 52 reality = src.telephone.text(a_list) 53 my_expectation = f"I got: {a_list}" 54 self.assertEqual(reality, my_expectation) 55 56 57# Exceptions seenI add a git_ commit message in the other terminal_
git commit -am 'add test_passing_a_list'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_a_dictionary
I can pass a dictionary (anything in curly braces { } separated by a comma) from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a test for a dictionary
50 def test_passing_a_list(self): 51 a_list = [1, 2, 3, 'n'] 52 reality = src.telephone.text(a_list) 53 my_expectation = f"I got: {a_list}" 54 self.assertEqual(reality, my_expectation) 55 56 def test_passing_a_dictionary(self): 57 reality = src.telephone.text( 58 { 59 'key1': 'value1', 60 'keyN': [0, 1, 2, 'n'], 61 } 62 ) 63 my_expectation = ( 64 "I got: " 65 "{key1: value1, keyN: [0, 1, 2, n]}" 66 ) 67 self.assertEqual(reality, my_expectation) 68 69 70# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" != 'I got: { key1: value1 , keyN : [0, 1, 2, n ]}'
GREEN: make it pass
I change my_expectation to match reality
56 def test_passing_a_dictionary(self):
57 reality = src.telephone.text(
58 {
59 'key1': 'value1',
60 'keyN': [0, 1, 2, 'n'],
61 }
62 )
63 my_expectation = (
64 "I got: "
65 # "{key1: value1, keyN: [0, 1, 2, n]}"
66 "{'key1': 'value1', 'keyN': [0, 1, 2, 'n']}"
67 )
68 self.assertEqual(reality, my_expectation)
69
70
71# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of the dictionary
56 def test_passing_a_dictionary(self): 57 a_dictionary = { 58 'key1': 'value1', 59 'keyN': [0, 1, 2, 'n'], 60 } 61 reality = src.telephone.text( 62 { 63 'key1': 'value1', 64 'keyN': [0, 1, 2, 'n'], 65 } 66 ) 67 my_expectation = ( 68 "I got: " 69 # "{key1: value1, keyN: [0, 1, 2, n]}" 70 "{'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" 71 ) 72 self.assertEqual(reality, my_expectation) 73 74 75# Exceptions seenI use the variable with string interpolation to remove repetition of the dictionary
56 def test_passing_a_dictionary(self): 57 a_dictionary = { 58 'key1': 'value1', 59 'keyN': [0, 1, 2, 'n'], 60 } 61 # reality = src.telephone.text( 62 # { 63 # 'key1': 'value1', 64 # 'keyN': [0, 1, 2, 'n'], 65 # } 66 # ) 67 reality = src.telephone.text(a_dictionary) 68 # my_expectation = ( 69 # "I got: " 70 # # "{key1: value1, keyN: [0, 1, 2, n]}" 71 # "{'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" 72 # ) 73 my_expectation = f'I got: {a_dictionary}' 74 self.assertEqual(reality, my_expectation) 75 76 77# Exceptions seenthe test is still green.
I remove the comments
56 def test_passing_a_dictionary(self): 57 a_dictionary = { 58 'key1': 'value1', 59 'keyN': [0, 1, 2, 'n'], 60 } 61 reality = src.telephone.text(a_dictionary) 62 my_expectation = f'I got: {a_dictionary}' 63 self.assertEqual(reality, my_expectation) 64 65 66# Exceptions seenI add a git_ commit message in the other terminal_
git commit --all --message 'add test_passing_a_dictionary'the terminal_ shows a summary of the changes then goes back to the command line.
test_passing_a_class
I can pass an object from a test to a function
RED: make it fail
I go back to the terminal_ that is running the tests
I add a failing test to see what happens when I pass a class from a test to the
textfunction, intest_telephone.py56 def test_passing_a_dictionary(self): 57 a_dictionary = { 58 'key1': 'value1', 59 'keyN': [0, 1, 2, 'n'], 60 } 61 reality = src.telephone.text(a_dictionary) 62 my_expectation = f'I got: {a_dictionary}' 63 self.assertEqual(reality, my_expectation) 64 65 def test_passing_a_class(self): 66 reality = src.telephone.text(object) 67 my_expectation = 'I got: object' 68 self.assertEqual(reality, my_expectation) 69 70 71# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'object'>" != 'I got: object'object is the mother class that all Python classes come from, and everything in Python_ is an object
GREEN: make it pass
I change my_expectation to match reality
65 def test_passing_a_class(self):
66 reality = src.telephone.text(object)
67 # my_expectation = 'I got: object'
68 my_expectation = "I got: <class 'object'>"
69 self.assertEqual(reality, my_expectation)
70
71
72# Exceptions seen
the test passes.
REFACTOR: make it better
I add another assertion with the
TestTelephoneclass totest_passing_a_classintest_telephone.py65 def test_passing_a_class(self): 66 reality = src.telephone.text(object) 67 # my_expectation = 'I got: object' 68 my_expectation = "I got: <class 'object'>" 69 self.assertEqual(reality, my_expectation) 70 71 reality = src.telephone.text(TestTelephone) 72 my_expectation = "I got: <class 'object'>" 73 self.assertEqual(reality, my_expectation) 74 75 76# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'tests.test_telephone.TestTelephone'>" != "I got: <class 'object'>"I change
my_expectationto matchreality71 reality = src.telephone.text(TestTelephone) 72 # my_expectation = "I got: <class 'object'>" 73 my_expectation = ( 74 "I got: <class" 75 f" 'tests.test_telephone.TestTelephone'>" 76 ) 77 self.assertEqual(reality, my_expectation) 78 79 80# Exceptions seenthe test passes. What does
tests.test_telephone.TestTelephonepoint to?testsis the folder_test_telephoneistest_telephone.pyin thetestsfolder_TestTelephoneis the class (object) that is defined on line 5 oftest_telephone.pyin thetestsfolder_
I add another assertion
71 reality = src.telephone.text(TestTelephone) 72 # my_expectation = "I got: <class 'object'>" 73 my_expectation = ( 74 "I got: <class" 75 f" 'tests.test_telephone.TestTelephone'>" 76 ) 77 self.assertEqual(reality, my_expectation) 78 79 reality = src.telephone.text(self) 80 my_expectation = "I got: self" 81 self.assertEqual(reality, my_expectation) 82 83 84# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: test_passing_a_class ( tests.test_telephone .TestTelephone.test_passing_a_class )' != 'I got: self'I change
my_expectationto matchreality79 reality = src.telephone.text(self) 80 # my_expectation = "I got: self" 81 my_expectation = ( 82 "I got: test_passing_a_class" 83 " (tests.test_telephone.TestTelephone" 84 ".test_passing_a_class)" 85 ) 86 self.assertEqual(reality, my_expectation) 87 88 89# Exceptions seenI add an assertion for bool (the class for booleans)
79 reality = src.telephone.text(self) 80 # my_expectation = "I got: self" 81 my_expectation = ( 82 "I got: test_passing_a_class" 83 " (tests.test_telephone.TestTelephone" 84 ".test_passing_a_class)" 85 ) 86 self.assertEqual(reality, my_expectation) 87 88 reality = src.telephone.text(bool) 89 my_expectation = 'I got: bool' 90 self.assertEqual(reality, my_expectation) 91 92 93# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'bool'>" != 'I got: bool'I change
my_expectationto matchreality88 reality = src.telephone.text(bool) 89 # my_expectation = 'I got: bool' 90 my_expectation = "I got: <class 'bool'>" 91 self.assertEqual(reality, my_expectation) 92 93 94# Exceptions seenthe test passes.
I add an assertion for int_ (the class for whole numbers without decimals)
88 reality = src.telephone.text(bool) 89 # my_expectation = 'I got: bool' 90 my_expectation = "I got: <class 'bool'>" 91 self.assertEqual(reality, my_expectation) 92 93 reality = src.telephone.text(int) 94 my_expectation = "I got: int" 95 self.assertEqual(reality, my_expectation) 96 97 98# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'int'>" != 'I got: int'I change
my_expectationto matchreality93 reality = src.telephone.text(int) 94 # my_expectation = "I got: int" 95 my_expectation = "I got: <class 'int'>" 96 self.assertEqual(reality, my_expectation) 97 98 99# Exceptions seenthe test passes
I add an assertion for float_ (the class for binary floating point decimal numbers)
93 reality = src.telephone.text(int) 94 # my_expectation = 'I got: int' 95 my_expectation = "I got: <class 'int'>" 96 self.assertEqual(reality, my_expectation) 97 98 reality = src.telephone.text(float) 99 my_expectation = "I got: float" 100 self.assertEqual(reality, my_expectation) 101 102 103# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'float'>" != 'I got: float'I change
my_expectationto matchreality98 reality = src.telephone.text(float) 99 # my_expectation = "I got: float" 100 my_expectation = "I got: <class 'float'>" 101 self.assertEqual(reality, my_expectation) 102 103 104# Exceptions seenthe test passes
I add an assertion for str_ (the class for anything in quotes)
98 reality = src.telephone.text(float) 99 # my_expectation = "I got: float" 100 my_expectation = "I got: <class 'float'>" 101 self.assertEqual(reality, my_expectation) 102 103 reality = src.telephone.text(str) 104 my_expectation = "I got: str" 105 self.assertEqual(reality, my_expectation) 106 107 108# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'str'>" != 'I got: str'I change
my_expectationto matchreality103 reality = src.telephone.text(str) 104 # my_expectation = "I got: str" 105 my_expectation = "I got: <class 'str'>" 106 self.assertEqual(reality, my_expectation) 107 108 109# Exceptions seenthe test passes
I add an assertion for tuple_ (the class for anything in parentheses
( )separated by a comma)103 reality = src.telephone.text(str) 104 # my_expectation = "I got: str" 105 my_expectation = "I got: <class 'str'>" 106 self.assertEqual(reality, my_expectation) 107 108 reality = src.telephone.text(tuple) 109 my_expectation = "I got: tuple" 110 self.assertEqual(reality, my_expectation) 111 112 113# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'tuple'>" != 'I got: tuple'I change
my_expectationto matchreality108 reality = src.telephone.text(tuple) 109 # my_expectation = "I got: tuple" 110 my_expectation = "I got: <class 'tuple'>" 111 self.assertEqual(reality, my_expectation) 112 113 114# Exceptions seenI add an assertion for list (the class for anything in square brackets ‘[ ]’)
108 reality = src.telephone.text(tuple) 109 # my_expectation = "I got: tuple" 110 my_expectation = "I got: <class 'tuple'>" 111 self.assertEqual(reality, my_expectation) 112 113 reality = src.telephone.text(list) 114 my_expectation = "I got: list" 115 self.assertEqual(reality, my_expectation) 116 117 118# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'list'>" != 'I got: list'I change
my_expectationto matchreality113 reality = src.telephone.text(list) 114 # my_expectation = "I got: list" 115 my_expectation = "I got: <class 'list'>" 116 self.assertEqual(reality, my_expectation) 117 118 119# Exceptions seenthe test passes
I add an assertion for set_ (the class anything in curly braces
{ }separated by a comma)113 reality = src.telephone.text(list) 114 # my_expectation = "I got: list" 115 my_expectation = "I got: <class 'list'>" 116 self.assertEqual(reality, my_expectation) 117 118 reality = src.telephone.text(set) 119 my_expectation = "I got: set" 120 self.assertEqual(reality, my_expectation) 121 122 123# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'set'>" != 'I got: set'I change
my_expectationto matchreality118 reality = src.telephone.text(set) 119 # my_expectation = "I got: set" 120 my_expectation = "I got: <class 'set'>" 121 self.assertEqual(reality, my_expectation) 122 123 124# Exceptions seenthe test passes
I add an assertion for dict (the class for any key-value pairs in curly braces ‘{ }’ separated by a comma)
118 reality = src.telephone.text(set) 119 # my_expectation = "I got: set" 120 my_expectation = "I got: <class 'set'>" 121 self.assertEqual(reality, my_expectation) 122 123 reality = src.telephone.text(dict) 124 my_expectation = "I got: dict" 125 self.assertEqual(reality, my_expectation) 126 127 128# Exceptions seenthe terminal_ is my friend, and shows AssertionError
AssertionError: "I got: <class 'dict'>" != 'I got: dict'I change
my_expectationto matchreality123 reality = src.telephone.text(dict) 124 # my_expectation = "I got: dict" 125 my_expectation = "I got: <class 'dict'>" 126 self.assertEqual(reality, my_expectation) 127 128 129# Exceptions seenthe test passes
I remove the commented lines
65 def test_passing_a_class(self): 66 reality = src.telephone.text(object) 67 my_expectation = "I got: <class 'object'>" 68 self.assertEqual(reality, my_expectation) 69 70 reality = src.telephone.text(TestTelephone) 71 my_expectation = ( 72 "I got: <class" 73 f" 'tests.test_telephone.TestTelephone'>" 74 ) 75 self.assertEqual(reality, my_expectation) 76 77 reality = src.telephone.text(self) 78 my_expectation = ( 79 "I got: test_passing_a_class" 80 " (tests.test_telephone.TestTelephone" 81 ".test_passing_a_class)" 82 ) 83 self.assertEqual(reality, my_expectation) 84 85 reality = src.telephone.text(bool) 86 my_expectation = "I got: <class 'bool'>" 87 self.assertEqual(reality, my_expectation) 88 89 reality = src.telephone.text(int) 90 my_expectation = "I got: <class 'int'>" 91 self.assertEqual(reality, my_expectation) 92 93 reality = src.telephone.text(float) 94 my_expectation = "I got: <class 'float'>" 95 self.assertEqual(reality, my_expectation) 96 97 reality = src.telephone.text(str) 98 my_expectation = "I got: <class 'str'>" 99 self.assertEqual(reality, my_expectation) 100 101 reality = src.telephone.text(tuple) 102 my_expectation = "I got: <class 'tuple'>" 103 self.assertEqual(reality, my_expectation) 104 105 reality = src.telephone.text(list) 106 my_expectation = "I got: <class 'list'>" 107 self.assertEqual(reality, my_expectation) 108 109 reality = src.telephone.text(set) 110 my_expectation = "I got: <class 'set'>" 111 self.assertEqual(reality, my_expectation) 112 113 reality = src.telephone.text(dict) 114 my_expectation = "I got: <class 'dict'>" 115 self.assertEqual(reality, my_expectation) 116 117 118# Exceptions seenI add a git_ commit message in the other terminal_
git commit -am 'add test_passing_a_class'the terminal_ shows a summary of the changes then goes back to the command line.
test_telephone
Time to write the program_ that makes the tests pass without looking at test_telephone.py
RED: make it fail
I close
test_telephone.pyin the editorI delete the text in
telephone.pyand the terminal_ shows 9 failures. I start with the last AttributeErrorFAILED ...test_passing_a_class - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_a_dictionary - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_a_float - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_a_list - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_a_string - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_a_tuple - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_an_integer - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_booleans - AttributeError: module 'src.telephone' has no attribute 'text' FAILED ...test_passing_none - AttributeError: module 'src.telephone' has no attribute 'text'
GREEN: make it pass
I add the name to
telephone.py1textthe terminal_ is my friend, and shows NameError
NameError: name 'text' is not definedI point it to None to define it
1# text 2text = Nonethe terminal_ is my friend, and shows TypeError
TypeError: 'NoneType' object is not callableI make
texta function to make it callable_1# text 2# text = None 3def text(): 4 return Nonethe terminal_ is my friend, and shows TypeError
TypeError: text() takes 0 positional arguments but 1 was givenI make the function take input
1# text 2# text = None 3# def text(): 4def text(value): 5 return Nonethe terminal_ is my friend, and shows AssertionError
AssertionError: None != 'I got: None'I copy the string_ from the terminal_ and paste it in the `return statement`_ to match the expectation of the test
1# text 2# text = None 3# def text(): 4def text(value): 5 # return None 6 return 'I got: None'the terminal_ is my friend, and shows AssertionError
AssertionError: 'I got: None' != 'I got: False'I add a `return statement`_ to see the difference between the input and the expected output (remember the identity function?)
1# text 2# text = None 3# def text(): 4def text(value): 5 # return None 6 # return 'I got: None' 7 return valuethe test summary info shows that every test has AssertionError
AssertionError: <class 'object'> != "I got: <class 'object'>" AssertionError: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']} != "I got: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" AssertionError: 1.234 != 'I got: 1.234' AssertionError: [1, 2, 3, 'n'] != "I got: [1, 2, 3, 'n']" AssertionError: 'hello' != 'I got: hello' AssertionError: (1, 2, 3, 'n') != "I got: (1, 2, 3, 'n')" AssertionError: 1234 != 'I got: 1234' AssertionError: False != 'I got: False' AssertionError: None != 'I got: None'they all expect the input (
value) as part of the messageI add a `return statement`_ with an f-string
1# text 2# text = None 3# def text(): 4def text(value): 5 # return None 6 # return 'I got: None' 7 # return value 8 return f'I got: {value}'and all the tests are passing! I am a programmer!!
I remove the commented lines
1def text(value): 2 return f'I got: {value}'
close the project
I close
telephone.pyin the editorI click in the terminal_ where the tests are running, then use q on the keyboard to leave the tests. The terminal_ goes back to the command line.
I `change directory`_ to the parent of
telephonecd ..the terminal_ shows
.../pumping_pythonI am back in the
pumping_pythondirectory_
review
Here are the tests I ran to see what happens when I pass Python basic data structures from a test to a program_ and place them in an f-string which is one way to do string interpolation
I also saw these Exceptions
code from the chapter
what is next?
You now know:
would you like to test using dictionaries and functions to make a person?
rate pumping python
If this has been a 7 star experience for you, please `CLICK HERE to leave a 5 star review of pumping python`_. It helps other people get into the book too.