how to pass values
I want to be able to send things from tests to the program I am testing and compare what I think will happen with the results I get. This helps me see what is the same, and what is different, the difference helps me know what to change to get what I want.
I use the identity function to show how input is passed from a test to a function in a module
preview
Here 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 self.assertEqual(
9 src.telephone.text("hello"),
10 "I received: hello"
11 )
12 self.assertEqual(
13 src.telephone.text("yes"),
14 "I received: yes"
15 )
16
17 def test_passing_a_class(self):
18 self.assertEqual(
19 src.telephone.text(object),
20 "I received: <class 'object'>"
21 )
22
23 def test_passing_none(self):
24 self.assertEqual(
25 src.telephone.text(None),
26 "I received: None"
27 )
28
29 def test_passing_a_boolean(self):
30 self.assertEqual(
31 src.telephone.text(True),
32 "I received: True"
33 )
34 self.assertEqual(
35 src.telephone.text(False),
36 "I received: False"
37 )
38
39 def test_passing_an_integer(self):
40 self.assertEqual(
41 src.telephone.text(1234),
42 "I received: 1234"
43 )
44
45 def test_passing_a_float(self):
46 self.assertEqual(
47 src.telephone.text(1.234),
48 "I received: 1.234"
49 )
50
51 def test_passing_a_tuple(self):
52 self.assertEqual(
53 src.telephone.text((1, 2, 3, "n")),
54 "I received: (1, 2, 3, 'n')"
55 )
56
57 def test_passing_a_list(self):
58 self.assertEqual(
59 src.telephone.text([1, 2, 3, "n"]),
60 "I received: [1, 2, 3, 'n']"
61 )
62
63 def test_passing_a_dictionary(self):
64 self.assertEqual(
65 src.telephone.text({
66 'key1': 'value1',
67 'keyN': [1, 2, 3, 'n'],
68 }),
69 "I received: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']}"
70 )
71
72
73# Exceptions seen
74# AssertionError
75# NameError
76# AttributeError
77# TypeError
start the project
I name this project
telephoneI open a terminal
then I make a directory for the project
mkdir telephonethe terminal goes back to the command line
.../pumping_pythonI change directory to the project
cd telephonethe terminal shows I am now in the
telephonefolder.../pumping_python/telephoneI make a folder for the source code
mkdir srcthe terminal goes back to the command line
.../pumping_python/telephoneI use touch to make an empty file for the program in the
srcfoldertouch src/telephone.pyon Windows without Windows Subsystem for Linux use
New-Item src/telephone.pyinstead oftouch src/telephone.pyNew-Item src/telephone.pythe terminal goes back to the command line
.../pumping_python/telephoneI make a directory for the tests
mkdir teststhe terminal goes back to the command line
I use touch to make an empty file in the
testsfolder to tell Python that it is a Python packageAttention
use 2 underscores (__) before and after
initfor__init__.pynot_init_.pytouch tests/__init__.pyon Windows without Windows Subsystem for Linux use
New-Item tests/__init__.pyinstead oftouch tests/__init__.pyNew-Item tests/__init__.pythe terminal goes back to the command line
I make an empty file for the actual test
touch tests/test_telephone.pyon Windows without Windows Subsystem for Linux use
New-Item tests/test_telephone.pyinstead oftouch 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 Visual Studio Code by typing
codeand the name of the file withcode tests/test_telephone.pytest_telephone.pyopens up in 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 make a virtual environment in the terminal
python3 -m venv .venvon Windows without Windows Subsystem for Linux use
python3 -m venv .venvinstead ofpython3 -m venv .venvpython -m venv .venvthe terminal takes some time then goes back to the command line
I activate the virtual environment
source .venv/bin/activateon Windows without Windows Subsystem for Linux use
.venv/bin/activate.ps1instead ofsource .venv/bin/activate.venv/scripts/activate.ps1the terminal shows
(.venv) .../pumping_python/telephoneI upgrade the Python package manager (pip) to the latest version
python3 -m pip install --upgrade pipthe terminal shows pip being uninstalled then installs the latest version or shows that it is already the latest version
I make a
requirements.txtfile for the Python programs my project needsecho "pytest-watch" > requirements.txtthe terminal goes back to the command line
I use pip to use the requirements file to install
pytest-watchpython3 -m pip install --requirement requirements.txton Windows without Windows Subsystem for Linux use
python -m pip install --requirement requirements.txtinstead ofpython3 -m pip install --requirement requirements.txtpython -m pip install --requirement requirements.txtthe terminal shows pip downloads and installs the Python programs that pytest-watch needs to run
I use pytest-watch to run the test
pytest-watchthe terminal shows
================================ 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 ============================I hold ctrl (Windows/Linux) or
option or command(MacOS) on the keyboard and use the mouse to click ontests/test_telephone.py:7to open it in the editorI add AssertionError to the list of Exceptions seen in
test_telephone.py7 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
RED: make it fail
I change test_failure to test_passing_a_string
1import unittest
2
3
4class TestTelephone(unittest.TestCase):
5
6 def test_passing_a_string(self):
7 self.assertEqual(
8 src.telephone.text("hello"),
9 "I received: hello"
10 )
11
12
13# Exceptions seen
NameError: name 'src' is not defined
there is no definition for src in test_telephone.py
GREEN: make it pass
I add the error to the list of Exceptions seen
13# Exceptions seen 14# AssertionError 15# NameErrorthen I add an import statement for the
telephonemodule which is in thesrcfolder, at the top of the file1import src.telephone 2import unittest 3 4 5class TestTelephone(unittest.TestCase):the terminal shows AttributeError
AttributeError: module 'src.telephone' has no attribute 'text'there is no definition for
textintelephone.pyin thesrcfolderI add the error to the list of Exceptions seen in
test_telephone.py14# Exceptions seen 15# AssertionError 16# NameError 17# AttributeErrorI open
telephone.pyfrom thesrcfolder in the editor, then add a name1textNameError: name 'text' is not definedthe name is in the file but I have not told Python what it means
I point
textto None1text = NoneTypeError: 'NoneType' object is not callableI add the error to the list of Exceptions seen in
test_telephone.py14# Exceptions seen 15# AssertionError 16# NameError 17# AttributeError 18# TypeErrorI change
textto a function intelephone.pyto make it callable1def text(): 2 return NoneTypeError: text() takes 0 positional arguments but 1 was givensrc.telephone.textwas called with"hello"as input but the definition of the function does not take any input - the parentheses are emptyI make the function take input and call it
the_input1def text(the_input): 2 return Nonethe terminal shows AssertionError
AssertionError: None != 'I received: hello'the test expects
'I received: hello'and thetextfunction returns NoneI copy the string from the terminal and paste it in the return statement to replace None
1def text(the_input): 2 return 'I received: hello'the test passes!
REFACTOR: make it better
The problem with this solution is that the text function does not care about the input it gets, it always returns 'I received: hello' when called. I want it to return the value it gets as part of the message.
RED: make it fail
I add a new assertion to test_passing_a_string in test_telephone.py
7 def test_passing_a_string(self):
8 self.assertEqual(
9 src.telephone.text("hello"),
10 "I received: hello"
11 )
12 self.assertEqual(
13 src.telephone.text("yes"),
14 "I received: yes"
15 )
16
17
18# Exceptions seen
the terminal shows AssertionError
AssertionError: 'I received: hello' != 'I received: yes'
the text function always returns 'I received: hello', the test expects 'I received: yes'
GREEN: make it pass
I change the return statement in telephone.py to match
1def text(the_input):
2 return 'I received: yes'
the terminal shows AssertionError
AssertionError: 'I received: yes' != 'I received: hello'
it did not work, my change broke the test that was passing before. The return statement has to use the input
string interpolation
I use an f-string which lets me add any values I want to a string
1def text(the_input):
2 return f'I received: {the_input}'
the test passes.
This is called string interpolation, I can use it to put values in strings.
A string is any characters inside quotes e.g.
'single quotes''''triple single quotes'''"double quotes""""triple double quotes"""
test_passing_a_class
RED: make it fail
I add a failing test in test_telephone.py to see what happens when I pass a class from a test to the text function
12 self.assertEqual(
13 src.telephone.text("yes"),
14 "I received: yes"
15 )
16
17 def test_passing_a_class(self):
18 self.assertEqual(
19 src.telephone.text(object),
20 "I received: object"
21 )
22
23
24# Exceptions seen
the terminal shows AssertionError
AssertionError: "I received: <class 'object'>" != 'I received: object'
object is the mother class that all Python classes come from
GREEN: make it pass
I change the expectation in the test to match the result
17 def test_passing_a_class(self):
18 self.assertEqual(
19 src.telephone.text(object),
20 "I received: <class 'object'>"
21 )
the test passes
REFACTOR: make it better
I add another assertion with the
TestTelephoneclass totest_passing_a_classintest_telephone.py17 def test_passing_a_class(self): 18 self.assertEqual( 19 src.telephone.text(object), 20 "I received: <class 'object'>" 21 ) 22 self.assertEqual( 23 src.telephone.text(TestTelephone), 24 "I received: <class 'object'>" 25 )the terminal shows AssertionError
AssertionError: "I received: <class 'tests.test_telephone.TestTelephone'>" != "I received: <class 'object'>"even though they are both classes, object and
TestTelephoneare differentI change the expectation
17 def test_passing_a_class(self): 18 self.assertEqual( 19 src.telephone.text(object), 20 "I received: <class 'object'>" 21 ) 22 self.assertEqual( 23 src.telephone.text(TestTelephone), 24 "I received: <class 'tests.test_telephone.TestTelephone'>" 25 )the test passes
test_passing_none
RED: make it fail
I add a new failing test for None in test_telephone.py
22 self.assertEqual(
23 src.telephone.text(TestTelephone),
24 "I received: <class 'tests.test_telephone.TestTelephone'>"
25 )
26
27 def test_passing_none(self):
28 self.assertEqual(
29 src.telephone.text(None),
30 "I received: 'None'"
31 )
the terminal shows AssertionError
AssertionError: 'I received: None' != "I received: 'None'"
GREEN: make it pass
I remove the quotes from around None in the expectation
27 def test_passing_none(self):
28 self.assertEqual(
29 src.telephone.text(None),
30 "I received: None"
31 )
32
33
34# Exceptions seen
the test passes.
test_passing_a_boolean
RED: make it fail
I add a test for booleans, first with an assertion for True
27 def test_passing_none(self):
28 self.assertEqual(
29 src.telephone.text(None),
30 "I received: None"
31 )
32
33 def test_passing_a_boolean(self):
34 self.assertEqual(
35 src.telephone.text(True),
36 "I received: 'True'"
37 )
the terminal shows AssertionError
AssertionError: "I received: True" != "I received: 'True'"
GREEN: make it pass
I change the expectation
33 def test_passing_a_boolean(self): 34 self.assertEqual( 35 src.telephone.text(True), 36 "I received: True" 37 )the test passes
-
33 def test_passing_a_boolean(self): 34 self.assertEqual( 35 src.telephone.text(True), 36 "I received: True" 37 ) 38 self.assertEqual( 39 src.telephone.text(False), 40 "I received: 'False'" 41 )the terminal shows AssertionError
AssertionError: "I received: False" != "I received: 'False'" I change the expectation
33 def test_passing_a_boolean(self): 34 self.assertEqual( 35 src.telephone.text(True), 36 "I received: True" 37 ) 38 self.assertEqual( 39 src.telephone.text(False), 40 "I received: False" 41 ) 42 43 44# Exceptions seenthe test passes.
test_passing_an_integer
RED: make it fail
I add a test for an integer (a whole number)
38 self.assertEqual(
39 src.telephone.text(False),
40 "I received: False"
41 )
42
43 def test_passing_an_integer(self):
44 self.assertEqual(
45 src.telephone.text(1234),
46 "I received: '1234'"
47 )
the terminal shows AssertionError
AssertionError: 'I received: 1234' != "I received: '1234'"
GREEN: make it pass
I remove the quotes from the expectation
43 def test_passing_an_integer(self):
44 self.assertEqual(
45 src.telephone.text(1234),
46 "I received: 1234"
47 )
48
49
50# Exceptions seen
the test passes.
test_passing_a_float
RED: make it fail
I add a test for a float (binary floating point decimal numbers)
43 def test_passing_an_integer(self):
44 self.assertEqual(
45 src.telephone.text(1234),
46 "I received: 1234"
47 )
48
49 def test_passing_a_float(self):
50 self.assertEqual(
51 src.telephone.text(1.234),
52 "I received: '1.234'"
53 )
the terminal shows AssertionError
AssertionError: 'I received: 1.234' != "I received: '1.234'"
GREEN: make it pass
I remove the quotes from the number
49 def test_passing_a_float(self):
50 self.assertEqual(
51 src.telephone.text(1.234),
52 "I received: 1.234"
53 )
54
55
56# Exceptions seen
the test passes.
test_passing_a_tuple
RED: make it fail
I add a test for a tuple (things in parentheses (()), separated by a comma)
49 def test_passing_a_float(self):
50 self.assertEqual(
51 src.telephone.text(1.234),
52 "I received: 1.234"
53 )
54
55 def test_passing_a_tuple(self):
56 self.assertEqual(
57 src.telephone.text((1, 2, 3, "n")),
58 "I received: '(1, 2, 3, n)'"
59 )
the terminal shows AssertionError
AssertionError: "I received: (1, 2, 3, 'n')" != "I received: '(1, 2, 3, n)'"
GREEN: make it pass
I change the expectation
55 def test_passing_a_tuple(self):
56 self.assertEqual(
57 src.telephone.text((1, 2, 3, "n")),
58 "I received: (1, 2, 3, 'n')"
59 )
the test passes.
test_passing_a_list
RED: make it fail
I add a test for a list (things in square brackets ([]), separated by a comma)
55 def test_passing_a_tuple(self):
56 self.assertEqual(
57 src.telephone.text((1, 2, 3, "n")),
58 "I received: (1, 2, 3, 'n')"
59 )
60
61 def test_passing_a_list(self):
62 self.assertEqual(
63 src.telephone.text([1, 2, 3, "n"]),
64 "I received: '[1, 2, 3, n]'"
65 )
the terminal shows AssertionError
AssertionError: "I received: [1, 2, 3, 'n']" != "I received: '[1, 2, 3, n]'"
GREEN: make it pass
I change the expectation to match reality
61 def test_passing_a_list(self):
62 self.assertEqual(
63 src.telephone.text([1, 2, 3, "n"]),
64 "I received: [1, 2, 3, 'n']"
65 )
the test passes.
test_passing_a_dictionary
RED: make it fail
I add a test for a dictionary (key-value pairs in curly braces ({}), separated by a comma)
61 def test_passing_a_list(self):
62 self.assertEqual(
63 src.telephone.text([1, 2, 3, "n"]),
64 "I received: [1, 2, 3, 'n']"
65 )
66
67 def test_passing_a_dictionary(self):
68 self.assertEqual(
69 src.telephone.text({
70 "key1": "value1",
71 "keyN": [0, 1, 2, "n"],
72 }),
73 "I received: '{key1: value1, keyN: [0, 1, 2, 'n']}'"
74 )
the terminal shows AssertionError
AssertionError: "I received: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" != "I received: '{key1: value1, keyN: [0, 1, 2, 'n']}'"
GREEN: make it pass
I change the expectation
67 def test_passing_a_dictionary(self):
68 self.assertEqual(
69 src.telephone.text({
70 "key1": "value1",
71 "keyN": [0, 1, 2, "n"],
72 }),
73 "I received: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']}"
74 )
75
76
77# Exceptions seen
the terminal shows all tests are passing.
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.pythen delete all the text in
telephone.py, the terminal shows 9 failures, I start with the last AttributeErrorAttributeError: module 'src.telephone' has no attribute 'text'
GREEN: make it pass
I add the name to
telephone.py1textNameError: name 'text' is not definedI point it to None
1text = NoneTypeError: 'NoneType' object is not callableI make
texta function1def text(): 2 return NoneTypeError: text() takes 0 positional arguments but 1 was givenI make the function take input
1def text(the_input): 2 return Nonethe terminal shows AssertionError
AssertionError: None != 'I received: None'I copy the string from the terminal and paste it in the return statement to match the expectation of the test
1def text(the_input): 2 return 'I received: None'the terminal shows AssertionError
AssertionError: 'I received: None' != 'I received: 1234'I add a return statement to see the difference between the input and the expected output
1def text(the_input): 2 return the_input 3 return 'I received: None'the test summary info shows that every test has AssertionError
AssertionError: True != 'I received: True' AssertionError: <class 'object'> != "I received: <class 'object'>" AssertionError: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']} != "I received: {'key1': 'value1', 'keyN': [0, 1, 2, 'n']}" AssertionError: 1.234 != 'I received: 1.234' AssertionError: [1, 2, 3, 'n'] != "I received: [1, 2, 3, 'n']" AssertionError: "hello" != 'I received: hello' AssertionError: (1, 2, 3, 'n') != "I received: (1, 2, 3, 'n')" AssertionError: 1234 != 'I received: 1234' AssertionError: None != 'I received: None'they all expect the input as part of the message
I remove the first return statement then make the second one use an f-string
1def text(the_input): 2 return f'I received: {the_input}'and all the tests are passing! Once again! I am a programmer!!
close the project
I close the file(s) I have open in the editor(s)
I click in the terminal and exit the tests with ctrl+c on the keyboard
I deactivate the virtual environment
deactivatethe terminal goes back to the command line,
(.venv)is no longer on the left side.../pumping_python/telephoneI 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 the following Exceptions
code from the chapter
what is next?
you have covered a bit so far and know