how to pass values
One of the things that happens when testing a program, is I send things (data) to the program and I check if what I think will happen is the same as the results I get back. Testing helps me answer 2 questions
what is the same?
what is different?
The difference helps me know what to change to get what I want.
This is the job of 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
I use the identity function in this chapter to show how something is passed 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 self.assertEqual(
9 src.telephone.text("hello"),
10 "I got: hello"
11 )
12 self.assertEqual(
13 src.telephone.text("yes"),
14 "I got: yes"
15 )
16
17 def test_passing_a_class(self):
18 self.assertEqual(
19 src.telephone.text(object),
20 "I got: <class 'object'>"
21 )
22
23 def test_passing_none(self):
24 self.assertEqual(
25 src.telephone.text(None),
26 "I got: None"
27 )
28
29 def test_passing_a_boolean(self):
30 self.assertEqual(
31 src.telephone.text(True),
32 "I got: True"
33 )
34 self.assertEqual(
35 src.telephone.text(False),
36 "I got: False"
37 )
38
39 def test_passing_an_integer(self):
40 self.assertEqual(
41 src.telephone.text(1234),
42 "I got: 1234"
43 )
44
45 def test_passing_a_float(self):
46 self.assertEqual(
47 src.telephone.text(1.234),
48 "I got: 1.234"
49 )
50
51 def test_passing_a_tuple(self):
52 self.assertEqual(
53 src.telephone.text((1, 2, 3, "n")),
54 "I got: (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 got: [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 got: {'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
I make a directory for the project
mkdir telephonethe terminal 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 make a Python file to hold the source code in the
srcdirectorytouch src/telephone.pyNote
on 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
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__.pyNote
on 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 a Python file for the tests in the
testsdirectorytouch tests/test_telephone.pyNote
on 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 use the terminal to open a file in the Integrated Development Environment (IDE) by typing the name of the program and the name of the file. That means when 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 make a requirements file for the Python packages I need, in the terminal
echo "pytest" > requirements.txtthe terminal goes back to the command line
I add pytest-watcher to the file
echo "pytest-watcher" >> requirements.txtthe terminal goes back to the command line
I setup the project with uv
uv initthe terminal shows
Initialized project `telephone`then goes back to the command line
I remove
main.pyfrom the project because I do not use itrm main.pythe terminal goes back to the command line
I install the Python packages I gave in the requirements file
uv add --requirement requirements.txtthe terminal shows it installed the Python packages
I use pytest-watcher to run the tests automatically
uv run pytest-watcher . --nowthe 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 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
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 got: 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 NameError to the list of Exceptions seen
13# Exceptions seen 14# AssertionError 15# NameErrorI 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 AttributeError 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 TypeError 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 got: hello'the test expects
'I got: hello'and thetextfunction returns NoneNote
the_inputis just the name I used for the input, I can use any name I wantI 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 self.assertEqual( 9 src.telephone.text("hello"), 10 "I got: hello" 11 ) 12 self.assertEqual( 13 src.telephone.text("yes"), 14 "I got: yes" 15 ) 16 17 18# Exceptions seenthe terminal shows AssertionError
AssertionError: 'I got: hello' != 'I got: yes'the
textfunction always returns'I got: hello', the test expects'I got: yes'I change the return statement in
telephone.pyto match1def text(the_input): 2 return 'I got: yes'the terminal shows AssertionError
AssertionError: 'I got: yes' != 'I got: 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 got: {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
7 def test_passing_a_string(self):
8 self.assertEqual(
9 src.telephone.text("hello"),
10 "I got: hello"
11 )
12 self.assertEqual(
13 src.telephone.text("yes"),
14 "I got: yes"
15 )
16
17 def test_passing_a_class(self):
18 self.assertEqual(
19 src.telephone.text(object),
20 "I got: object"
21 )
22
23
24# Exceptions seen
the terminal shows AssertionError
AssertionError: "I got: <class 'object'>" != 'I got: 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 got: <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 got: <class 'object'>" 21 ) 22 self.assertEqual( 23 src.telephone.text(TestTelephone), 24 "I got: <class 'object'>" 25 )the terminal shows AssertionError
AssertionError: "I got: <class 'tests.test_telephone.TestTelephone'>" != "I got: <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 got: <class 'object'>" 21 ) 22 self.assertEqual( 23 src.telephone.text(TestTelephone), 24 "I got: <class 'tests.test_telephone.TestTelephone'>" 25 )the test passes. What does
tests.test_telephone.TestTelephonepoint to?
test_passing_none
RED: make it fail
I add a new failing test for None (it is the simplest Python data structure) in test_telephone.py
17 def test_passing_a_class(self):
18 self.assertEqual(
19 src.telephone.text(object),
20 "I got: <class 'object'>"
21 )
22 self.assertEqual(
23 src.telephone.text(TestTelephone),
24 "I got: <class 'tests.test_telephone.TestTelephone'>"
25 )
26
27 def test_passing_none(self):
28 self.assertEqual(
29 src.telephone.text(None),
30 "I got: 'None'"
31 )
32
33
34# Exceptions seen
the terminal shows AssertionError
AssertionError: 'I got: None' != "I got: '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 got: 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 got: None"
31 )
32
33 def test_passing_a_boolean(self):
34 self.assertEqual(
35 src.telephone.text(True),
36 "I got: 'True'"
37 )
38
39
40# Exceptions seen
the terminal shows AssertionError
AssertionError: "I got: True" != "I got: '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 got: True" 37 )the test passes
-
33 def test_passing_a_boolean(self): 34 self.assertEqual( 35 src.telephone.text(True), 36 "I got: True" 37 ) 38 self.assertEqual( 39 src.telephone.text(False), 40 "I got: 'False'" 41 )the terminal shows AssertionError
AssertionError: "I got: False" != "I got: 'False'" I change the expectation
33 def test_passing_a_boolean(self): 34 self.assertEqual( 35 src.telephone.text(True), 36 "I got: True" 37 ) 38 self.assertEqual( 39 src.telephone.text(False), 40 "I got: 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)
33 def test_passing_a_boolean(self):
34 self.assertEqual(
35 src.telephone.text(True),
36 "I got: True"
37 )
38 self.assertEqual(
39 src.telephone.text(False),
40 "I got: False"
41 )
42
43 def test_passing_an_integer(self):
44 self.assertEqual(
45 src.telephone.text(1234),
46 "I got: '1234'"
47 )
48
49
50# Exceptions seen
the terminal shows AssertionError
AssertionError: 'I got: 1234' != "I got: '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 got: 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 got: 1234"
47 )
48
49 def test_passing_a_float(self):
50 self.assertEqual(
51 src.telephone.text(1.234),
52 "I got: '1.234'"
53 )
54
55
56# Exceptions seen
the terminal shows AssertionError
AssertionError: 'I got: 1.234' != "I got: '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 got: 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 got: 1.234"
53 )
54
55 def test_passing_a_tuple(self):
56 self.assertEqual(
57 src.telephone.text((1, 2, 3, "n")),
58 "I got: '(1, 2, 3, n)'"
59 )
60
61
62# Exceptions seen
the terminal shows AssertionError
AssertionError: "I got: (1, 2, 3, 'n')" != "I got: '(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 got: (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 got: (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 got: '[1, 2, 3, n]'"
65 )
66
67
68# Exceptions seen
the terminal shows AssertionError
AssertionError: "I got: [1, 2, 3, 'n']" != "I got: '[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 got: [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 got: [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 got: '{key1: value1, keyN: [0, 1, 2, n]}'"
74 )
75
76
77# Exceptions seen
the terminal 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 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 got: {'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 to define it
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(value): 2 return Nonethe terminal 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 shows AssertionError
AssertionError: 'I got: None' != 'I got: 1234'I add a return statement to see the difference between the input and the expected output
1def text(value): 2 return value 3 return 'I got: None'the test summary info shows that every test has AssertionError
AssertionError: True != 'I got: True' 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: None != 'I got: 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(value): 2 return f'I got: {value}'and all the tests are passing! I am a programmer!!
close the project
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
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