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) oroption
(mac) on the keyboard and use the mouse to click ontests/test_telephone.py:7
to open it in the editorthen change
True
toFalse
to make the test passand change
test_failure
totest_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
moduleimport 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 Nonetext = 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 callabledef 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 thisI 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 AttributeErrorAttributeError: 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?