how to pass values


I want to test passing values to programs. When testing, I want to be able to send input from my test to the program and see the results. This helps me see what is the same, and what is different, the difference gives helps me know what to change to get what I want.

requirements

  • I open a terminal to run makePythonTdd.sh with telephone as the name of the project

    ./makePythonTdd.sh telephone
    

    on Windows without Windows Subsystem Linux use makePythonTdd.ps1

    ./makePythonTdd.ps1 telephone
    

    it makes the folders and files that are needed, installs packages, runs the first test, and the terminal shows AssertionError

    E       AssertionError: True is not false
    
    tests/test_telephone.py:7: AssertionError
    
  • I hold ctrl (windows/linux) or option (mac) on the keyboard and use the mouse to click on tests/test_telephone.py:7 to open it in the editor

  • then I change True to False to make the test pass

    7        self.assertFalse(False)
    
  • I change the name of the class to match the CapWords format

    4class TestTelephone(unittest.TestCase):
    

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        )
    

    the terminal shows NameError

    NameError: name 'src' is not defined
    

green: make it pass

  • I add it to the list of Exceptions encountered

    13# Exceptions Encountered
    14# AssertionError
    15# NameError
    
  • then I add an import statement for the telephone module at the top of the file

    Note

    the …(ellipsis) represents code that does not need to change in this part

    1import src.telephone
    2import unittest
    3
    4
    5class TestTelephone(unittest.TestCase):
    6
    7    ...
    

    the terminal shows AttributeError

    AttributeError: module 'src.telephone' has no attribute 'text'
    
  • I add it to the list of Exceptions encountered in test_telephone.py

    14# Exceptions Encountered
    15# AssertionError
    16# NameError
    17# AttributeError
    
  • I click on telephone.py in the src folder to open it in the editor, then add a name

    1text
    

    the terminal shows NameError

    NameError: name 'text' is not defined
    
  • I point text to None

    1text = None
    

    the terminal shows TypeError

    TypeError: 'NoneType' object is not callable
    
  • I add it to the list of Exceptions encountered in test_telephone.py

    14# Exceptions Encountered
    15# AssertionError
    16# NameError
    17# AttributeError
    18# TypeError
    
  • I change text to a function to make it callable in telephone.py

    1def text():
    2    return None
    

    the terminal shows TypeError

    TypeError: text() takes 0 positional arguments but 1 was given
    

    src.telephone.text was called with "hello" as input but the definition of the function does not take any input - the parentheses are empty

  • I make the function take input and call it value

    1def text(value):
    2    return None
    

    the terminal shows AssertionError

    AssertionError: None != 'I received: hello'
    
  • when I copy the string from the terminal and paste it in the return statement to replace None

    1def text(value):
    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 receives and will always return 'I received: hello' when it is called. I want it to return the value it receives 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 Encountered
19...

the terminal shows AssertionError

AssertionError: 'I received: hello' != 'I received: yes'

green: make it pass

  • I change the return statement in telephone.py

    1def text(value):
    2    return 'I received: yes'
    

    the terminal shows AssertionError

    AssertionError: 'I received: yes' != 'I received: hello'
    

    this will not work, my change breaks the test that was passing before. The return statement has to use the input

  • I use an f-string which allows me add any values I want to a string

    1def text(value):
    2    return f'I received: {value}'
    

    the test passes. This is called string interpolation, I can use it to put values in strings. A string is any characters in between quotes e.g.

    • 'a string made with single quotes'

    • "a string made with double quotes"

    • '''a string made with triple single quotes'''

    • """a string made with triple double quotes"""


I want to see what happens when I pass other Python basic data structures to the program

test_passing_a_class

red: make it fail

I add a failing test for a class in test_telephone.py

 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: object"
21        )
22
23
24# Exceptions Encountered
25...

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 make the expectation match reality

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 TestTelephone class to test_passing_a_class

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 '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 TestTelephone are different. I 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

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        )
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        )

the test passes.

test_passing_a_boolean

red: make it fail

I add a test for booleans, first with an assertion for True

Note

the …(ellipsis) represents code that does not need to change in this part

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

  • I add an assertion for False

    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        )
    

    the 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 received: True"
37        )
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        )

the test passes.

test_passing_a_float

red: make it fail

I add a test for a float (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        )

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 Encountered
78...

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.py

  • then delete all the text in telephone.py, the terminal shows AttributeError

    AttributeError: module 'src.telephone' has no attribute 'text'
    

green: make it pass

  • I add the name to telephone.py

    1text
    

    the terminal shows NameError

    NameError: name 'text' is not defined
    

    I point it to None

    1text = None
    

    the terminal shows TypeError

    TypeError: 'NoneType' object is not callable
    

    I make text a function

    1def text():
    2    return None
    

    the terminal shows TypeError

    TypeError: text() takes 0 positional arguments but 1 was given
    

    I make the function take input

    1def text(argument):
    2    return None
    

    the 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(argument):
    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(argument):
    2    return argument
    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(argument):
    2    return f'I received: {argument}'
    

    and all the tests are passing! Once again! I am a programmer!!


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

I also ran into the following Exceptions

Would you like to test making a person?


Click Here to see the code from this chapter