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 to show how I can pass input data from a test to a function in a module.
preview
These are the tests I have by the end of the chapter
1import src.telephone
2import unittest
3
4
5class TestTelephone(unittest.TestCase):
6
7 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 def test_passing_none(self):
17 reality = src.telephone.text(None)
18 my_expectation = 'I got: None'
19 self.assertEqual(reality, my_expectation)
20
21 def test_passing_booleans(self):
22 reality = src.telephone.text(False)
23 my_expectation = 'I got: False'
24 self.assertEqual(reality, my_expectation)
25
26 reality = src.telephone.text(True)
27 my_expectation = 'I got: True'
28 self.assertEqual(reality, my_expectation)
29
30 def test_passing_an_integer(self):
31 reality = src.telephone.text(1234)
32 my_expectation = 'I got: 1234'
33 self.assertEqual(reality, my_expectation)
34
35 def test_passing_a_float(self):
36 reality = src.telephone.text(1.234)
37 my_expectation = 'I got: 1.234'
38 self.assertEqual(reality, my_expectation)
39
40 def test_passing_a_tuple(self):
41 reality = src.telephone.text((1, 2, 3, 'n'))
42 my_expectation = "I got: (1, 2, 3, 'n')"
43 self.assertEqual(reality, my_expectation)
44
45 def test_passing_a_list(self):
46 reality = src.telephone.text([1, 2, 3, "n"])
47 my_expectation = "I got: [1, 2, 3, 'n']"
48 self.assertEqual(reality, my_expectation)
49
50 def test_passing_a_dictionary(self):
51 reality = src.telephone.text(
52 {
53 'key1': 'value1',
54 'keyN': [0, 1, 2, 'n'],
55 }
56 )
57 my_expectation = (
58 "I got: "
59 "{'key1': 'value1', 'keyN': [0, 1, 2, 'n']}"
60 )
61 self.assertEqual(reality, my_expectation)
62
63 def test_passing_a_class(self):
64 reality = src.telephone.text(object)
65 my_expectation = "I got: <class 'object'>"
66 self.assertEqual(reality, my_expectation)
67
68 reality = src.telephone.text(TestTelephone)
69 my_expectation = (
70 "I got: <class "
71 "'tests.test_telephone.TestTelephone'>"
72 )
73 self.assertEqual(reality, my_expectation)
74
75
76# Exceptions seen
77# AssertionError
78# NameError
79# AttributeError
80# TypeError
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 thesrcfoldermv 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 packageDanger
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
testsdirectorytouch 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.pyVisual 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 'initialize project'the terminal shows
[main (root-commit) a0b12c3] initialize 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 file1import 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.pyI like to sort my import statements alphabetically
the 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 None1text = 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 callable1def text(): 2 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
1def text(the_input): 2 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
1def text(the_input): 2 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 match1def text(the_input): 2 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
1def text(the_input): 2 return f'I got: {the_input}'the test passes.
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 the 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 self.assertEqual(reality, my_expectation)
22
23
24# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of None
18 def test_passing_none(self): 19 none = None 20 reality = src.telephone.text(None) 21 my_expectation = 'I got: None' 22 self.assertEqual(reality, my_expectation) 23 24 25# Exceptions seenI use the variable with an f-string to remove repetition of None
18 def test_passing_none(self): 19 none = None 20 # reality = src.telephone.text(None) 21 reality = src.telephone.text(none) 22 # my_expectation = 'I got: None' 23 my_expectation = f'I got: {none}' 24 self.assertEqual(reality, my_expectation) 25 26 27# Exceptions seenthe test is still green.
I remove the comments
18 def test_passing_none(self): 19 none = None 20 reality = src.telephone.text(none) 21 my_expectation = f'I got: {none}' 22 self.assertEqual(reality, my_expectation) 23 24 25# 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 none = None 20 reality = src.telephone.text(none) 21 my_expectation = f'I got: {none}' 22 self.assertEqual(reality, my_expectation) 23 24 def test_passing_booleans(self): 25 reality = src.telephone.text(False) 26 my_expectation = 'I got: "False"' 27 self.assertEqual(reality, my_expectation) 28 29 30# 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
24 def test_passing_booleans(self):
25 reality = src.telephone.text(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
-
24 def test_passing_booleans(self): 25 reality = src.telephone.text(False) 26 my_expectation = 'I got: False' 27 self.assertEqual(reality, my_expectation) 28 29 reality = src.telephone.text(True) 30 my_expectation = 'I got: "True"' 31 self.assertEqual(reality, my_expectation) 32 33 34# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 'I got: True' != 'I got: "True"'
I remove the quotes around True in my_expectation
29 reality = src.telephone.text(True) 30 my_expectation = 'I got: True' 31 self.assertEqual(reality, my_expectation) 32 33 34# Exceptions seenthe test passes.
I add a variable to use to remove repetition of False
24 def test_passing_booleans(self): 25 false = False 26 reality = src.telephone.text(False) 27 my_expectation = 'I got: False' 28 self.assertEqual(reality, my_expectation)I use the variable with a string interpolation to remove repetition of False
24 def test_passing_booleans(self): 25 false = False 26 # reality = src.telephone.text(False) 27 reality = src.telephone.text(false) 28 # my_expectation = 'I got: False' 29 my_expectation = f'I got: {false}' 30 self.assertEqual(reality, my_expectation)the test is still green.
I add a variable to use to remove repetition of True
24 def test_passing_booleans(self): 25 false = False 26 # reality = src.telephone.text(False) 27 reality = src.telephone.text(false) 28 # my_expectation = 'I got: False' 29 my_expectation = f'I got: {false}' 30 self.assertEqual(reality, my_expectation) 31 32 true = True 33 reality = src.telephone.text(True) 34 my_expectation = 'I got: True' 35 self.assertEqual(reality, my_expectation)I use the variable with an f-string to remove repetition of True
32 true = True 33 # reality = src.telephone.text(True) 34 reality = src.telephone.text(true) 35 # my_expectation = 'I got: True' 36 my_expectation = f'I got: {true}' 37 self.assertEqual(reality, my_expectation) 38 39 40# Exceptions seenstill green.
I remove the comments
24 def test_passing_booleans(self): 25 false = False 26 reality = src.telephone.text(false) 27 my_expectation = f'I got: {false}' 28 self.assertEqual(reality, my_expectation) 29 30 true = True 31 reality = src.telephone.text(true) 32 my_expectation = f'I got: {true}' 33 self.assertEqual(reality, my_expectation) 34 35 36# 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 with no 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
30 true = True 31 reality = src.telephone.text(true) 32 my_expectation = f'I got: {true}' 33 self.assertEqual(reality, my_expectation) 34 35 def test_passing_an_integer(self): 36 reality = src.telephone.text(1234) 37 my_expectation = 'I got: "1234"' 38 self.assertEqual(reality, my_expectation) 39 40 41# 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
35 def test_passing_an_integer(self):
36 reality = src.telephone.text(1234)
37 my_expectation = 'I got: 1234'
38 self.assertEqual(reality, my_expectation)
39
40
41# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of
123435 def test_passing_an_integer(self): 36 an_integer = 1234 37 reality = src.telephone.text(1234) 38 my_expectation = 'I got: 1234' 39 self.assertEqual(reality, my_expectation) 40 41 42# Exceptions seenI use the variable with string interpolation to remove repetition of
123435 def test_passing_an_integer(self): 36 an_integer = 1234 37 # reality = src.telephone.text(1234) 38 reality = src.telephone.text(an_integer) 39 # my_expectation = 'I got: 1234' 40 my_expectation = f'I got: {an_integer}' 41 self.assertEqual(reality, my_expectation) 42 43 44# Exceptions seenthe test is still green.
I remove the comments
35 def test_passing_an_integer(self): 36 an_integer = 1234 37 reality = src.telephone.text(an_integer) 38 my_expectation = f'I got: {an_integer}' 39 self.assertEqual(reality, my_expectation) 40 41 42# 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)
35 def test_passing_an_integer(self): 36 an_integer = 1234 37 reality = src.telephone.text(an_integer) 38 my_expectation = f'I got: {an_integer}' 39 self.assertEqual(reality, my_expectation) 40 41 def test_passing_a_float(self): 42 reality = src.telephone.text(1.234) 43 my_expectation = 'I got: "1.234"' 44 self.assertEqual(reality, my_expectation) 45 46 47# 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
41 def test_passing_a_float(self):
42 reality = src.telephone.text(1.234)
43 my_expectation = 'I got: 1.234'
44 self.assertEqual(reality, my_expectation)
45
46
47# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of
1.23441 def test_passing_a_float(self): 42 a_float = 1.234 43 reality = src.telephone.text(1.234) 44 my_expectation = 'I got: "1.234"' 45 self.assertEqual(reality, my_expectation) 46 47 48# Exceptions seenI use the variable with an f-string to remove repetition of
1.23441 def test_passing_a_float(self): 42 a_float = 1.234 43 # reality = src.telephone.text(1.234) 44 reality = src.telephone.text(a_float) 45 # my_expectation = 'I got: "1.234"' 46 my_expectation = f'I got: {a_float}' 47 self.assertEqual(reality, my_expectation) 48 49 50# Exceptions seenthe test is still green.
I remove the comments
41 def test_passing_a_float(self): 42 a_float = 1.234 43 reality = src.telephone.text(a_float) 44 my_expectation = f'I got: {a_float}' 45 self.assertEqual(reality, my_expectation) 46 47 48# Exceptions seenI add a git commit message in the other terminal
git commit --all --message '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
41 def test_passing_a_float(self): 42 a_float = 1.234 43 reality = src.telephone.text(a_float) 44 my_expectation = f'I got: {a_float}' 45 self.assertEqual(reality, my_expectation) 46 47 def test_passing_a_tuple(self): 48 reality = src.telephone.text((1, 2, 3, 'n')) 49 my_expectation = 'I got: (1, 2, 3, n)' 50 self.assertEqual(reality, my_expectation) 51 52 53# 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
47 def test_passing_a_tuple(self):
48 reality = src.telephone.text((1, 2, 3, 'n'))
49 my_expectation = "I got: (1, 2, 3, 'n')"
50 self.assertEqual(reality, my_expectation)
51
52
53# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of the tuple
47 def test_passing_a_tuple(self): 48 a_tuple = (1, 2, 3, 'n') 49 reality = src.telephone.text((1, 2, 3, 'n')) 50 my_expectation = "I got: (1, 2, 3, 'n')" 51 self.assertEqual(reality, my_expectation) 52 53 54# Exceptions seenI use the variable with string interpolation to remove repetition of the tuple
47 def test_passing_a_tuple(self): 48 a_tuple = (1, 2, 3, 'n') 49 # reality = src.telephone.text((1, 2, 3, 'n')) 50 reality = src.telephone.text(a_tuple) 51 # my_expectation = "I got: (1, 2, 3, 'n')" 52 my_expectation = f"I got: {a_tuple}" 53 self.assertEqual(reality, my_expectation) 54 55 56# Exceptions seenthe test is still green.
I remove the comments
47 def test_passing_a_tuple(self): 48 a_tuple = (1, 2, 3, 'n') 49 reality = src.telephone.text(a_tuple) 50 my_expectation = f"I got: {a_tuple}" 51 self.assertEqual(reality, my_expectation) 52 53 54# Exceptions seenI add a git commit message in the other terminal
git commit -am '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
47 def test_passing_a_tuple(self): 48 a_tuple = (1, 2, 3, 'n') 49 reality = src.telephone.text(a_tuple) 50 my_expectation = f"I got: {a_tuple}" 51 self.assertEqual(reality, my_expectation) 52 53 def test_passing_a_list(self): 54 reality = src.telephone.text([1, 2, 3, 'n']) 55 my_expectation = 'I got: [1, 2, 3, "n"]' 56 self.assertEqual(reality, my_expectation) 57 58 59# 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
53 def test_passing_a_list(self):
54 reality = src.telephone.text([1, 2, 3, "n"])
55 my_expectation = "I got: [1, 2, 3, 'n']"
56 self.assertEqual(reality, my_expectation)
57
58
59# 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
53 def test_passing_a_list(self): 54 a_list = [1, 2, 3, 'n'] 55 reality = src.telephone.text([1, 2, 3, 'n']) 56 my_expectation = "I got: [1, 2, 3, 'n']" 57 self.assertEqual(reality, my_expectation) 58 59 60# Exceptions seenI use the variable with an f-string to remove repetition of the list
53 def test_passing_a_list(self): 54 a_list = [1, 2, 3, 'n'] 55 # reality = src.telephone.text([1, 2, 3, 'n']) 56 reality = src.telephone.text(a_list) 57 # my_expectation = "I got: [1, 2, 3, 'n']" 58 my_expectation = f"I got: {a_list}" 59 self.assertEqual(reality, my_expectation) 60 61 62# Exceptions seenthe test is still green.
I remove the comments
53 def test_passing_a_list(self): 54 a_list = [1, 2, 3, 'n'] 55 reality = src.telephone.text(a_list) 56 my_expectation = f"I got: {a_list}" 57 self.assertEqual(reality, my_expectation) 58 59 60# Exceptions seenI add a git commit message in the other terminal
git commit --all --message '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
53 def test_passing_a_list(self): 54 a_list = [1, 2, 3, 'n'] 55 reality = src.telephone.text(a_list) 56 my_expectation = f"I got: {a_list}" 57 self.assertEqual(reality, my_expectation) 58 59 def test_passing_a_dictionary(self): 60 reality = src.telephone.text( 61 { 62 'key1': 'value1', 63 'keyN': [0, 1, 2, 'n'], 64 } 65 ) 66 my_expectation = ( 67 "I got: " 68 "{key1: value1, keyN: [0, 1, 2, n]}" 69 ) 70 self.assertEqual(reality, my_expectation) 71 72 73# 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
59 def test_passing_a_dictionary(self):
60 reality = src.telephone.text(
61 {
62 'key1': 'value1',
63 'keyN': [0, 1, 2, 'n'],
64 }
65 )
66 my_expectation = (
67 "I got: "
68 "{'key1': 'value1', "
69 "'keyN': [0, 1, 2, 'n']}"
70 )
71 self.assertEqual(reality, my_expectation)
72
73
74# Exceptions seen
the test passes.
REFACTOR: make it better
I add a variable to use to remove repetition of the dictionary
59 def test_passing_a_dictionary(self): 60 a_dictionary = { 61 'key1': 'value1', 62 'keyN': [0, 1, 2, 'n'], 63 } 64 reality = src.telephone.text( 65 { 66 'key1': 'value1', 67 'keyN': [0, 1, 2, 'n'], 68 } 69 ) 70 my_expectation = ( 71 "I got: " 72 "{'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" 73 ) 74 self.assertEqual(reality, my_expectation) 75 76 77# Exceptions seenI use the variable with string interpolation to remove repetition of the dictionary
59 def test_passing_a_dictionary(self): 60 a_dictionary = { 61 'key1': 'value1', 62 'keyN': [0, 1, 2, 'n'], 63 } 64 # reality = src.telephone.text( 65 # { 66 # 'key1': 'value1', 67 # 'keyN': [0, 1, 2, 'n'], 68 # } 69 # ) 70 reality = src.telephone.text(a_dictionary) 71 # my_expectation = ( 72 # "I got: " 73 # "{'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" 74 # ) 75 my_expectation = f'I got: {a_dictionary}' 76 self.assertEqual(reality, my_expectation) 77 78 79# Exceptions seenthe test is still green.
I remove the comments
59 def test_passing_a_dictionary(self): 60 a_dictionary = { 61 'key1': 'value1', 62 'keyN': [0, 1, 2, 'n'], 63 } 64 reality = src.telephone.text(a_dictionary) 65 my_expectation = f'I got: {a_dictionary}' 66 self.assertEqual(reality, my_expectation) 67 68 69# Exceptions seenI add a git commit message in the other terminal
git commit -am '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.py59 def test_passing_a_dictionary(self): 60 a_dictionary = { 61 'key1': 'value1', 62 'keyN': [0, 1, 2, 'n'], 63 } 64 reality = src.telephone.text(a_dictionary) 65 my_expectation = f'I got: {a_dictionary}' 66 self.assertEqual(reality, my_expectation) 67 68 def test_passing_a_class(self): 69 reality = src.telephone.text(object) 70 my_expectation = 'I got: object' 71 self.assertEqual(reality, my_expectation) 72 73 74# 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
68 def test_passing_a_class(self):
69 reality = src.telephone.text(object)
70 my_expectation = "I got: <class 'object'>"
71 self.assertEqual(reality, my_expectation)
72
73
74# Exceptions seen
the test passes.
REFACTOR: make it better
I add another assertion with the
TestTelephoneclass totest_passing_a_classintest_telephone.py68 def test_passing_a_class(self): 69 reality = src.telephone.text(object) 70 my_expectation = "I got: <class 'object'>" 71 self.assertEqual(reality, my_expectation) 72 73 reality = src.telephone.text(TestTelephone) 74 my_expectation = "I got: <class 'object'>" 75 self.assertEqual(reality, my_expectation) 76 77 78# 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 matchreality73 reality = src.telephone.text(TestTelephone) 74 my_expectation = ( 75 "I got: <class " 76 "'tests.test_telephone.TestTelephone'>" 77 ) 78 self.assertEqual(reality, my_expectation) 79 80 81# Exceptions seenthe test passes. What does
tests.test_telephone.TestTelephonepoint to?testsis the foldertest_telephoneistest_telephone.pyin thetestsfolderTestTelephoneis the class (object) that is defined on line 5 oftest_telephone.pyin thetestsfolder
I add another assertion
73 reality = src.telephone.text(TestTelephone) 74 my_expectation = ( 75 "I got: <class " 76 "'tests.test_telephone.TestTelephone'>" 77 ) 78 self.assertEqual(reality, my_expectation) 79 80 reality = src.telephone.text(self) 81 my_expectation = "I got: self" 82 self.assertEqual(reality, my_expectation) 83 84 85# 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 matchreality80 reality = src.telephone.text(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 a git commit message in the other terminal
git commit --all --message '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
1text = Nonethe terminal is my friend, and shows TypeError
TypeError: 'NoneType' object is not callableI make
texta function to make it callable1def text(): 2 return Nonethe terminal is my friend, and shows TypeError
TypeError: text() takes 0 positional arguments but 1 was givenI make the function take input
1def text(value): 2 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
1def text(value): 2 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?)
1def text(value): 2 return value 3 return 'I got: None'the 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 remove the first return statement then make the second one use an f-string
1def text(value): 2 return f'I got: {value}'and all the tests are passing! I am a programmer!!
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.