how to pass values



I want to test passing values to programs

test_passing_a_string

red: make it fail

  • 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 change True to False to make the test pass

  • and change test_failure to test_passing_a_string

    class TestTelephone(unittest.TestCase):
    
        def test_passing_a_string(self):
            self.assertEqual(
                src.telephone.text("hello"),
                "I received: hello"
            )
    

    the terminal shows NameError

    NameError: name 'src' is not defined
    

green: make it pass

  • I add it to the list of Exceptions encountered

    # Exceptions Encountered
    # AssertionError
    # NameError
    
  • then add an import statement for the telephone module

    import src.telephone
    import unittest
    

    which gives me AttributeError

    AttributeError: module 'src.telephone' has no attribute 'text'
    
  • another one for the list of Exceptions encountered

    # Exceptions Encountered
    # AssertionError
    # NameError
    # AttributeError
    
  • I add a name to telephone.py

    text
    

    and the terminal shows NameError

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

    text = None
    

    and get TypeError

    TypeError: 'NoneType' object is not callable
    
  • which I add to the list of Exceptions encountered

    # Exceptions Encountered
    # AssertionError
    # NameError
    # AttributeError
    # TypeError
    
  • I change text to a function to make it callable

    def text():
        return None
    

    and the terminal shows another TypeError

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

    src.telephone.text was called with input but the definition of the function does not allow this

  • I make it take a value

    def text(value):
        return None
    

    and get AssertionError

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

    def text(value):
        return 'I received: hello'
    

    the test passes!

refactor: make it better

The problem with this solution is that text is a singleton function, it does not care about the input and will always return 'I received: hello'. 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

def test_passing_a_string(self):
    self.assertEqual(
        src.telephone.text("hello"),
        "I received: hello"
    )
    self.assertEqual(
        src.telephone.text("yes"),
        "I received: yes"
    )

which gives me AssertionError

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

green: make it pass

  • when I make the return statement match the expectation

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

    I get another AssertionError

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

    this will not work, the return statement has to use the input

  • I use an f-string to add values to the string

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

    and the terminal shows a passing test. This solution is called string interpolation


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

test_passing_a_class

red: make it fail

I add a failing test for a class

def test_passing_a_class(self):
    self.assertEqual(
        src.telephone.text(object),
        "I received: object"
    )

the terminal shows AssertionError

AssertionError: "I received: <class 'object'>" != 'I received: object'

object is the mother of all Python classes, they inherit from it by default

green: make it pass

I make the expectation match reality and the test passes

def test_passing_a_class(self):
    self.assertEqual(
        src.telephone.text(object),
        "I received: <class 'object'>"
    )

refactor: make it better

then add another assertion for a different class

def test_passing_a_class(self):
    self.assertEqual(
        src.telephone.text(TestTelephone),
        "I received: <class 'object'>"
    )
    self.assertEqual(
        src.telephone.text(TestTelephone),
        "I received: <class 'object'>"
    )

which gives me AssertionError

AssertionError: "I received: <class 'tests.test_telephone.TestTelephone'>" != "I received: <class 'object'>"

when I change the name of the class to match reality

self.assertEqual(
    src.telephone.text(TestTelephone),
    "I received: <class 'tests.test_telephone.TestTelephone'>"
)

the test passes.

test_passing_none

red: make it fail

I add a new failing test for None

def test_passing_none(self):
    self.assertEqual(
        src.telephone.text(None),
        "I received: 'None'"
    )

and 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

self.assertEqual(
    src.telephone.text(None),
    "I received: None"
)

and the test passes.

test_passing_a_boolean

red: make it fail

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

def test_passing_a_boolean(self):
    self.assertEqual(
        src.telephone.text(True),
        "I received: 'True'"
    )

the terminal shows AssertionError

AssertionError: "I received: True" != "I received: 'True'"

green: make it pass

  • I change the expectation

    def test_passing_a_boolean(self):
        self.assertEqual(
            src.telephone.text(True),
            "I received: True"
        )
    

    and the test passes

  • then I add an assertion for False

    def test_passing_a_boolean(self):
        self.assertEqual(
            src.telephone.text(True),
            "I received: True"
        )
        self.assertEqual(
            src.telephone.text(False),
            "I received: 'False'"
        )
    

    which gives me AssertionError

    AssertionError: "I received: False" != "I received: 'False'"
    
  • when I change the expectation

    self.assertEqual(
        src.telephone.text(False),
        "I received: False"
    )
    

    the terminal shows passing tests.

test_passing_an_integer

I also add a test for an integer

def test_passing_an_integer(self):
    self.assertEqual(
        src.telephone.text(1234),
        "I received: '1234'"
    )

and the terminal shows AssertionError

AssertionError: 'I received: 1234' != "I received: '1234'"

green: make it pass

I remove the quotes from the expectation

def test_passing_an_integer(self):
    self.assertEqual(
        src.telephone.text(1234),
        "I received: 1234"
    )

and the terminal shows passing tests.

test_passing_a_float

red: make it fail

I add a test for a float

def test_passing_a_float(self):
    self.assertEqual(
        src.telephone.text(1.234),
        "I received: '1.234'"
    )

and get AssertionError

AssertionError: 'I received: 1.234' != "I received: '1.234'"

green: make it pass

I remove the quotes from the number

def test_passing_a_float(self):
    self.assertEqual(
        src.telephone.text(1.234),
        "I received: 1.234"
    )

and the terminal shows passing tests.

test_passing_a_tuple

red: make it fail

I add a test for a tuple

def test_passing_a_tuple(self):
    self.assertEqual(
        src.telephone.text((1, 2, 3, "n")),
        "I received: '(1, 2, 3, n)'"
    )

the terminal shows AssertionError

AssertionError: "I received: (1, 2, 3, 'n')" != "I received: '(1, 2, 3, n)'"

green: make it pass

I make the expectation match reality

def test_passing_a_tuple(self):
    self.assertEqual(
        src.telephone.text((1, 2, 3, "n")),
        "I received: (1, 2, 3, 'n')"
    )

and the terminal shows green again.

test_passing_a_list

red: make it fail

I add a test for a list

def test_passing_a_list(self):
    self.assertEqual(
        src.telephone.text([1, 2, 3, "n"]),
        "I received: '[1, 2, 3, n]'"
    )

and get 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

def test_passing_a_list(self):
    self.assertEqual(
        src.telephone.text([1, 2, 3, "n"]),
        "I received: [1, 2, 3, 'n']"
    )

and the terminal shows green again.

test_passing_a_dictionary

red: make it fail

I add a test for a dictionary

def test_passing_a_dictionary(self):
    self.assertEqual(
        src.telephone.text({
            "key1": "value1",
            "keyN": "valueN",
        }),
        "I received: '{key1: value1, keyN: valueN}'"
    )

and the terminal shows AssertionError

AssertionError: "I received: {'key1': 'value1', 'keyN': 'valueN'}" != "I received: '{key1: value1, keyN: valueN}'"

green: make it pass

when I make the expectation match reality

def test_passing_a_dictionary(self):
    self.assertEqual(
        src.telephone.text({
            "key1": "value1",
            "keyN": "valueN"
        }),
        "I received: {'key1': 'value1', 'keyN': 'valueN'}"
    )

the terminal shows all tests are passing.


test_telephone

Time to write the program that makes the tests in test_telephone.py pass without looking at them

red: make it fail

  • I close test_telephone.py

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

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

green: make it pass

  • I add the name

    text
    

    and get NameError

    NameError: name 'text' is not defined
    

    I point it to None

    text = None
    

    and the terminal shows TypeError

    TypeError: 'NoneType' object is not callable
    

    when I make it a function

    def text():
        return None
    

    the terminal shows another TypeError

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

    I add a positional argument to the function’s signature

    def text(argument):
        return None
    

    and the terminal shows AssertionError

    AssertionError: None != 'I received: None'
    
  • I copy the string from the terminal, paste it in the return statement to match the expectation of the test

    def text(argument):
        return 'I received: None'
    

    and get another AssertionError

    AssertionError: 'I received: None' != 'I received: 1234'
    
  • I add a return statement to see the difference between the input and the expected output

    def text(argument):
        return argument
        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': 'valueN'} != "I received: {'key1': 'value1', 'keyN': 'valueN'}"
    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

    def text(argument):
        return f'I received: {argument}'
    

    and all tests pass!


review

Here are the tests I ran to see what happens when I pass Python 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?


how to pass values: tests and solution