how to make a person¶
This is an exercise in making dictionaries with functions
test_function_w_keyword_arguments¶
red: make it fail¶
I open a terminal to run makePythonTdd.sh with
person
as the name of the project./makePythonTdd.sh person
on Windows without Windows Subsystem Linux use makePythonTdd.ps1
./makePythonTdd.ps1 person
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_person.py:7: AssertionError
I hold
ctrl
(windows/linux) oroption
(mac) on the keyboard and use the mouse to click ontests/test_person.py:7
to open it in the editorthen change
True
toFalse
to make the test passand change
test_failure
totest_function_w_keyword_arguments
class TestPersonFactory(unittest.TestCase): def test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory(), None )
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 I add an import statement for the
person
moduleimport src.person import unittest
and get AttributeError
AttributeError: module 'src.person' has no attribute 'factory'
I add it to the list of Exceptions encountered
# Exceptions Encountered # AssertionError # NameError # AttributeError
then open
person.py
from thesrc
folder to add a functiondef factory(): return None
the terminal shows a passing test
I want the function to take in a keyword argument named
first_name
def test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory( first_name='first_name', ), None )
the terminal shows TypeError
TypeError: factory() got an unexpected keyword argument 'first_name'
I add the error to the list of Exceptions encountered
# Exceptions Encountered # AssertionError # NameError # AttributeError # TypeError
then add the name as an input parameter to the function
def factory(first_name): return None
and the test passes
I want the function to take in a keyword argument named
last_name
def test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory( first_name='first_name', last_name='last_name', ), None )
this gives me TypeError
TypeError: factory() got an unexpected keyword argument 'last_name'
when I add the name to the function definition
def factory(first_name, last_name): return None
the terminal shows a passing test
I want the function to take in a keyword argument named
sex
def test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory( first_name='first_name', last_name='last_name', sex='M', ), None )
the terminal shows TypeError
TypeError: factory() got an unexpected keyword argument 'sex'
I add the name as input to the function
def factory( first_name, last_name, sex ): return None
and the terminal shows a passing test
I want the function to take in a keyword argument and give it the result of calling another one
def test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory( first_name='first_name', last_name='last_name', sex='M', year_of_birth=this_year(), ), None )
the terminal shows NameError
NameError: name 'this_year' is not defined
I add the new function above the class definition
import unittest import src.person def this_year(): return None class TestPersonFactory(unittest.TestCase): ..
and get TypeError
TypeError: factory() got an unexpected keyword argument 'year_of_birth'
when I add the name to the function definition
def factory( first_name, last_name, sex, year_of_birth ): return None
the test passes
I want the
factory
function to return a dictionary as output, I change the expectation in the assertiondef test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory( first_name='first_name', last_name='last_name', sex='M', year_of_birth=this_year(), ), dict() )
and the terminal shows AssertionError
AssertionError: None != {}
when I make the return statement match the expectation
def factory( first_name, last_name, sex, year_of_birth ): return {}
the test passes because
{}
anddict()
do the same thingI want the dictionary to have a key named
first_name
with the same value as what was given in the call to thefactory
functiondef test_function_w_keyword_arguments(self): self.assertEqual( src.person.factory( first_name='first_name', last_name='last_name', sex='M', year_of_birth=this_year(), ), dict( first_name='first_name', ) )
the terminal shows AssertionError
AssertionError: {} != {'first_name': 'first_name'}
I copy the value from the right then use it to replace the empty dictionary in the return statement
def factory( first_name, last_name, sex, year_of_birth ): return {'first_name': 'first_name'}
and the test passes
'first_name'
appears twice in the test, which means I have to make a change in 2 places if I want a different value for it. I add a variable to remove the repetitiondef test_function_w_keyword_arguments(self): first_name = 'first_name' self.assertEqual( src.person.factory( first_name=first_name, last_name='last_name', sex='M', year_of_birth=this_year() ), dict( first_name=first_name, ) )
and the test is still green. I now only need to change the value of
first_name
in one placedef test_function_w_keyword_arguments(self): first_name = 'jane' ...
and the terminal shows AssertionError
AssertionError: {'first_name': 'first_name'} != {'first_name': 'jane'}
I copy the value from the terminal then use it to replace the one in the return statement
def factory( first_name, last_name, sex, year_of_birth ): return {'first_name': 'jane}
and the test is green again
I want the dictionary to have a key named
last_name
with the same value as what was given in the call to thefactory
functiondef test_function_w_keyword_arguments(self): first_name = 'jane' self.assertEqual( src.person.factory( first_name=first_name, last_name='last_name', sex='M', year_of_birth=this_year() ), dict( first_name=first_name, last_name='last_name', ) )
and get AssertionError
AssertionError: {'first_name': 'jane'} != {'first_name': 'jane', 'last_name': 'last_name'}
I copy the value from the terminal then use it to change the return statement
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'last_name' }
and the terminal shows green again
'last_name'
happens twice in the test, I add a variable to remove the duplication like I did withfirst_name
def test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'last_name' self.assertEqual( src.person.factory( first_name=first_name, last_name=last_name, sex='M', year_of_birth=this_year() ), dict( first_name=first_name, last_name=last_name, ) )
then change the value
def test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' ...
and get AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'last_name'} != {'first_name': 'jane', 'last_name': 'doe'}
I copy the value from the terminal then use it to replace the return statement
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': last_name, }
and the test passes
I add a key named
sex
to the dictionary with the same value as what was given in the call to thefactory
functiondef test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' self.assertEqual( src.person.factory( first_name=first_name, last_name=last_name, sex='M', year_of_birth=this_year() ), dict( first_name=first_name, last_name=last_name, sex='M', ) )
the terminal shows AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'doe'} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M'}
I copy the value from the right side then use it to replace the return statement
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'doe', 'sex': 'M' }
and the terminal shows green again
I add a variable to remove the repetition in the test
def test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' sex = 'M' self.assertEqual( src.person.factory( first_name=first_name, last_name=last_name, sex=sex, year_of_birth=this_year() ), dict( first_name=first_name, last_name=last_name, sex=sex, ) )
still green
when I change the value of the
sex
variabledef test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' sex = 'F' ...
the terminal shows AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M'} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F'}
I copy the value from the right side then use it to replace the return statement
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'doe', 'sex': 'F' }
and the test is green again
I add
age
to the expectation with a calculationdef test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' sex = 'F' self.assertEqual( src.person.factory( first_name=first_name, last_name=last_name, sex=sex, year_of_birth=this_year(), ), dict( first_name=first_name, last_name=last_name, sex=sex, age=this_year()-this_year(), ) )
the terminal shows TypeError
TypeError: unsupported operand type(s) for -: 'NoneType' and 'NoneType'
I cannot do subtraction with None and I want the value for the current year
I add an import statement
import datetime import src.person import unittest
datetime is a module from the python standard library that is used for dates and times
I change the return statement in the
this_year
function to make it return the current yeardef this_year(): return datetime.datetime.now().year
datetime.datetime.now().year
returns theyear
attribute of thedatetime
object returned by the now method of thedatetime
class, from the datetime module. I can also use the today method to get the same valuedef this_year(): return datetime.datetime.today().year
the terminal shows AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F'} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 0}
the new dictionary has a value for
age
when I copy it from the terminal to replace the return statement
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 0 }
the test passes
I add a variable to remove duplication
def test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' sex = 'F' year_of_birth = this_year() self.assertEqual( src.person.factory( first_name=first_name, last_name=last_name, sex=sex, year_of_birth=year_of_birth, ), dict( first_name=first_name, last_name=last_name, sex=sex, age=this_year()-year_of_birth, ) )
and the test is still green
refactor: make it better¶
I add an import statement to use random values
import datetime import random import src.person import unittest
random is a module from the python standard library that is used to make fake random numbers
I use it for the
year_of_birth
variabledef test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' sex = 'F' year_of_birth = random.randint( this_year()-120, this_year() ) ...
random.randint(this_year()-120, this_year())
gives me a random number from 120 years ago, up to and including the current year which is returned bythis_year()
. When the age is not0
, the terminal shows AssertionErrorAssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 0} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 2} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 0} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 7} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 0} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 14} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 0} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 60}
I use the age calculation from the expectation
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': this_year() - year_of_birth, }
and get NameError
NameError: name 'this_year' is not defined
because I called a function that does not exist in
person.py
. I change the call to thethis_year()
function to the return statement fromtest_person.py
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'doe', 'sex': 'F, 'age': datetime.datetime.now().year - year_of_birth, }
and the terminal shows another NameError
NameError: name 'datetime' is not defined. Did you forget to import 'datetime'
I add an import statement to
person.py
import datetime def factory( ...
and the terminal shows a passing test
I add randomness to the
sex
variabledef test_function_w_keyword_arguments(self): first_name = 'jane' last_name = 'doe' sex = random.choice(('F', 'M')) year_of_birth = random.randint( this_year()-120, this_year() ) ...
random.choice(('F', 'M'))
randomly gives meF
orM
and the terminal shows random success or AssertionErrorAssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 56} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 56} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 76} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 76} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 109} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 109} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 115} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 115}
when I change the return statement to use the
sex
input parameterdef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': 'doe', 'sex': sex, 'age': datetime.datetime.now().year - year_of_birth, }
the test passes with no more random failures
I use random.choice with the
last_name
variabledef test_function_w_keyword_arguments(self): first_name = 'jane' last_name = random.choice(( 'doe', 'smith', 'blow', 'public', )) sex = random.choice(('F', 'M')) year_of_birth = random.randint( this_year()-120, this_year() ) ...
and get random success or AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 51} != {'first_name': 'jane', 'last_name': 'smith', 'sex': 'F', 'age': 51} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 54} != {'first_name': 'jane', 'last_name': 'blow', 'sex': 'M', 'age': 54} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 110} != {'first_name': 'jane', 'last_name': 'public', 'sex': 'F', 'age': 110} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 116} != {'first_name': 'jane', 'last_name': 'public', 'sex': 'M', 'age': 116}
I change the return statement to use the
last_name
input parameterdef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'jane', 'last_name': last_name, 'sex': sex, 'age': datetime.datetime.today().year - year_of_birth, }
and the test is green again
I do the same thing for the
first_name
variabledef test_function_w_keyword_arguments(self): first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) last_name = random.choice(( 'doe', 'smith', 'blow', 'public', )) sex = random.choice(('F', 'M')) year_of_birth = random.randint( this_year()-120, this_year() ) ...
and get random success or AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'public', 'sex': 'F', 'age': 6} != {'first_name': 'john', 'last_name': 'public', 'sex': 'F', 'age': 6} AssertionError: {'first_name': 'jane', 'last_name': 'smith', 'sex': 'M', 'age': 19} != {'first_name': 'person', 'last_name': 'smith', 'sex': 'M', 'age': 19} AssertionError: {'first_name': 'jane', 'last_name': 'blow', 'sex': 'M', 'age': 59} != {'first_name': 'person', 'last_name': 'blow', 'sex': 'M', 'age': 59} AssertionError: {'first_name': 'jane', 'last_name': 'smith', 'sex': 'F', 'age': 117} != {'first_name': 'joe', 'last_name': 'smith', 'sex': 'F', 'age': 117}
when I change the return statement to use the
first_name
input parameterdef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': last_name, 'sex': sex, 'age': datetime.datetime.today().year - year_of_birth, }
the terminal shows a passing test.
test_function_w_default_keyword_arguments¶
I want to see what would happen when I try to make a person without a value for the last_name
red: make it fail¶
I make a copy of
test_function_w_keyword_arguments
and paste it belowthen change the name to
test_function_w_default_keyword_arguments
and remove thelast_name
variabledef test_function_w_default_keyword_arguments(self): first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) sex = 'M' year_of_birth = random.randint( this_year()-120, this_year() ) ...
to get NameError
NameError: name 'last_name' is not defined
green: make it pass¶
I remove
last_name
from the call to thefactory
functionself.assertEqual( src.person.factory( first_name=first_name, year_of_birth=year_of_birth, sex=sex, ), dict( first_name=first_name, last_name=last_name, sex=sex, age=this_year() - year_of_birth ) )
and get TypeError
TypeError: factory() missing 1 required positional argument: 'last_name'
the
factory
function is called with 3 arguments in the test but the definition expects 4I add a default value for
last_name
def factory( first_name, last_name=None, sex, year_of_birth ): ...
and the terminal shows a SyntaxError
SyntaxError: parameter without a default follows parameter with a default
I add it to the list of Exceptions encountered
# Exceptions Encountered # AssertionError # NameError # AttributeError # TypeError # SyntaxError
then add a default value for the
sex
parameterdef factory( first_name, last_name=None, sex=None, year_of_birth ): ...
and get another SyntaxError
SyntaxError: parameter without a default follows parameter with a default
I give the
year_of_birth
parameter a default valuedef factory( first_name, last_name=None, sex=None, year_of_birth=None ): ...
and the terminal shows NameError
NameError: name 'last_name' is not defined
the value for the
last_name
key in the expected dictionary points to a variable that no longer existsI change the expectation for it
self.assertEqual( src.person.factory( first_name=first_name, sex=sex, year_of_birth=year_of_birth, ), dict( first_name=first_name, last_name='doe', sex=sex, age=this_year()-year_of_birth, ) )
and the terminal shows AssertionError
AssertionError: {'first_name': 'joe', 'last_name': None, 'sex': 'F', 'age': 28} != {'first_name': 'joe', 'last_name': 'doe', 'sex': 'F', 'age': 28} AssertionError: {'first_name': 'person', 'last_name': None, 'sex': 'M', 'age': 33} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 33} AssertionError: {'first_name': 'jane', 'last_name': None, 'sex': 'F', 'age': 70} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'F', 'age': 70} AssertionError: {'first_name': 'john', 'last_name': None, 'sex': 'M', 'age': 83} != {'first_name': 'john', 'last_name': 'doe', 'sex': 'M', 'age': 83}
the
factory
function returns a dictionary with a value of None forlast_name
and the test expects'doe'
When I make the default value for
last_name
in the function match the expectationdef factory( first_name, last_name='doe', sex, year_of_birth ): ...
the terminal shows passing tests. When the
factory
function is called with no value for thelast_name
argument, it uses'doe'
because that is the default value in the function signature, it is same as calling it withlast_name='doe'
src.person.factory( first_name=first_name, sex=sex, year_of_birth=year_of_birth, last_name='doe', )
I remove the
sex
variable to see what would happen if I do not know its valuedef test_function_w_default_keyword_arguments(self): first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) year_of_birth = random.randint( this_year()-120, this_year() ) ...
the terminal shows NameError
NameError: name 'sex' is not defined
I remove it from the call to the
factory
functionself.assertEqual( src.person.factory( first_name=first_name, year_of_birth=year_of_birth, ), { 'first_name': first_name, 'last_name': 'doe', 'sex': sex, 'age': this_year()-year_of_birth, } )
and get the same NameError
NameError: name 'sex' is not defined
the value in the dictionary still uses the variable I removed. I change the expectation
self.assertEqual( src.person.factory( first_name=first_name, year_of_birth=year_of_birth, ), { 'first_name': first_name, 'last_name': 'doe', 'sex': 'M', 'age': this_year()-year_of_birth, } )
and get AssertionError
AssertionError: {'first_name': 'joe', 'last_name': 'doe', 'sex': None, 'age': 4} != {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 4} AssertionError: {'first_name': 'jane', 'last_name': 'doe', 'sex': None, 'age': 32} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 32} AssertionError: {'first_name': 'john', 'last_name': 'doe', 'sex': None, 'age': 45} != {'first_name': 'john', 'last_name': 'doe', 'sex': 'M', 'age': 45} AssertionError: {'first_name': 'person', 'last_name': 'doe', 'sex': None, 'age': 58} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 58}
the
factory
function returns a dictionary with None as the value forsex
and the test expects'M'
when I add a default value to match the expectation
def factory( first_name, last_name='doe', sex='M', year_of_birth=None ): ...
the terminal shows passing tests. When the
factory
function is called with no value for thesex
argument, it uses'M'
because that is the default value in the function signature, it is same as calling it withsex='M'
src.person.factory( first_name=first_name, year_of_birth=year_of_birth, last_name='doe', sex='M', )
since the values are the same as the default values, I can call the function without them
src.person.factory( first_name=first_name, year_of_birth=year_of_birth, )
refactor: make it better¶
first_name
andyear_of_birth
are made the same way in both tests, I can remove this repetition with class attributes... class TestPerson(unittest.TestCase): first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) year_of_birth = random.randint( this_year()-120, this_year() ) ...
then use them in the tests with
self.
the same way I use theassert
methodsdef test_function_w_keyword_arguments(self): first_name = self.first_name last_name = random.choice(( 'doe', 'smith', 'blow', 'public', )) sex = random.choice(('F', 'M')) year_of_birth = self.year_of_birth ... def test_function_w_default_keyword_arguments(self): first_name = self.first_name year_of_birth = self.year_of_birth ...
the terminal still shows green
since the variables point to class attributes, I can use them directly
def test_function_w_keyword_arguments(self): first_name = self.first_name last_name = random.choice(( 'doe', 'smith', 'blow', 'public', )) sex = random.choice(('F', 'M')) year_of_birth = self.year_of_birth self.assertEqual( src.person.factory( first_name=self.first_name, last_name=last_name, sex=sex, year_of_birth=self.year_of_birth ), dict( first_name=self.first_name, last_name=last_name, sex=sex, age=this_year()-self.year_of_birth, ) ) def test_function_w_default_keyword_arguments(self): first_name = self.first_name year_of_birth = self.year_of_birth self.assertEqual( src.person.factory( first_name=self.first_name, year_of_birth=self.year_of_birth ), dict( first_name=self.first_name, last_name='doe', sex='M', age=this_year()-self.year_of_birth, ) )
all tests are still passing
I remove the variables because they are no longer used
def test_function_w_keyword_arguments(self): last_name = random.choice(( 'doe', 'smith', 'blow', 'public', )) sex = random.choice(('F', 'M')) self.assertEqual( src.person.factory( first_name=self.first_name, last_name=last_name, sex=sex, year_of_birth=self.year_of_birth ), dict( first_name=self.first_name, last_name=last_name, sex=sex, age=this_year()-self.year_of_birth, ) ) def test_function_w_default_keyword_arguments(self): self.assertEqual( src.person.factory( first_name=self.first_name, year_of_birth=self.year_of_birth ), dict( first_name=self.first_name, last_name='doe', sex='M', age=this_year()-self.year_of_birth, ) )
both tests have the same random values for
first_name
andyear_of_birth
, they were not always the same before the change. I can use the unittest.TestCase.setUp method which runs before every test to make sure they are assigned to new random values before each testclass TestPerson(unittest.TestCase): def setUp(self): first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) year_of_birth = random.randint( this_year()-120, this_year() ) def test_function_w_keyword_arguments(self): ...
the terminal shows AttributeError
AttributeError: 'TestPerson' object has no attribute 'first_name'
because there is no longer a class attribute with the name, it is local to the unittest.TestCase.setUp method and the other methods cannot reach it
I add
self.
to make it a class attributedef setUp(self): self.first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) year_of_birth = random.randint( this_year()-120, this_year() )
and get another AttributeError
AttributeError: 'TestPerson' object has no attribute 'year_of_birth'
same problem, same solution
def setUp(self): self.first_name = random.choice(( 'jane', 'joe', 'john', 'person', )) self.year_of_birth = random.randint( this_year()-120, this_year() )
and both tests are green again.
self.first_name
andself.year_of_birth
are given random values before the first test, then given random values again before the second test
test_person_tests¶
red: make it fail¶
I close
test_person.py
I want to write the solution without looking at the tests and delete all the text in
person.py
, the terminal shows AttributeErrorAttributeError: module 'src.person' has no attribute 'factory'
green: make it pass¶
I add the name
factory
the terminal shows NameError
NameError: name 'factory' is not defined
I point it to None
factory = None
which gives me TypeError
TypeError: 'NoneType' object is not callable
when I make it a function
def factory(): return None
the terminal shows another TypeError
TypeError: factory() got an unexpected keyword argument 'first_name'
I add the keyword argument to the function definition
def factory(first_name): return None
and get TypeError
TypeError: factory() got an unexpected keyword argument 'last_name'
I add the keyword argument
def factory(first_name, last_name): return None
and the terminal shows another TypeError
TypeError: factory() got an unexpected keyword argument 'sex'
when I add the keyword argument
def factory(first_name, last_name, sex): return None
I still get TypeError
TypeError: factory() got an unexpected keyword argument 'year_of_birth'
I add the missing keyword argument
def factory( first_name, last_name, sex, year_of_birth ): return None
and the terminal shows AssertionError
AssertionError: None != {'first_name': 'john', 'last_name': 'blow', 'sex': 'M', 'age': 20} AssertionError: None != {'first_name': 'john', 'last_name': 'smith', 'sex': 'F', 'age': 31} AssertionError: None != {'first_name': 'jane', 'last_name': 'blow', 'sex': 'M', 'age': 55} AssertionError: None != {'first_name': 'person', 'last_name': 'smith', 'sex': 'F', 'age': 97}
I copy the value from the terminal to replace None in the return statement
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20 }
which gives me another AssertionError
AssertionError: {'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'jane', 'last_name': 'smith', 'sex': 'M', 'age': 50} AssertionError: {'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'jane', 'last_name': 'doe', 'sex': 'M', 'age': 73} AssertionError: {'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'john', 'last_name': 'smith', 'sex': 'M', 'age': 77} AssertionError: {'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'jane', 'last_name': 'public', 'sex': 'M', 'age': 98}
the values for
first_name
,last_name
,sex
andage
changeI make the dictionary in the return statement use the
first_name
input parameter instead of a hardcoded valuedef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': 'blow', 'sex': 'F', 'age': 20 }
and still have AssertionError
AssertionError: {'first_name': 'person', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'person', 'last_name': 'public', 'sex': 'M', 'age': 69} AssertionError: {'first_name': 'joe', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'joe', 'last_name': 'blow', 'sex': 'M', 'age': 97} AssertionError: {'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'john', 'last_name': 'smith', 'sex': 'M', 'age': 74} AssertionError: {'first_name': 'john', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'john', 'last_name': 'public', 'sex': 'M', 'age': 19}
the
last_name
,sex
andage
changeI use the
last_name
input parameter in the return statementdef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': last_name, 'sex': 'F', 'age': 20 }
and get another AssertionError
AssertionError: {'first_name': 'jane', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'jane', 'last_name': 'blow', 'sex': 'M', 'age': 3} AssertionError: {'first_name': 'joe', 'last_name': 'smith', 'sex': 'F', 'age': 20} != {'first_name': 'joe', 'last_name': 'smith', 'sex': 'M', 'age': 118} AssertionError: {'first_name': 'joe', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'joe', 'last_name': 'blow', 'sex': 'M', 'age': 19} AssertionError: {'first_name': 'joe', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'joe', 'last_name': 'blow', 'sex': 'M', 'age': 95}
the values for
sex
andage
changeWhen I add the
sex
input parameter to the return statementdef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': last_name, 'sex': sex, 'age': 20 }
the terminal shows another AssertionError
AssertionError: {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 20} != {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 1} AssertionError: {'first_name': 'joe', 'last_name': 'public', 'sex': 'F', 'age': 20} != {'first_name': 'joe', 'last_name': 'public', 'sex': 'F', 'age': 90} AssertionError: {'first_name': 'joe', 'last_name': 'blow', 'sex': 'F', 'age': 20} != {'first_name': 'joe', 'last_name': 'blow', 'sex': 'F', 'age': 113} AssertionError: {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 20} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 58}
the
age
is differentI add the
year_of_birth
input parameter to the return statementdef factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': last_name, 'sex': sex, 'age': year_of_birth, }
and get AssertionError
AssertionError: {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 2022} != {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 2} AssertionError: {'first_name': 'jane', 'last_name': 'smith', 'sex': 'M', 'age': 2024} != {'first_name': 'jane', 'last_name': 'smith', 'sex': 'M', 'age': 0} AssertionError: {'first_name': 'jane', 'last_name': 'blow', 'sex': 'F', 'age': 1981} != {'first_name': 'jane', 'last_name': 'blow', 'sex': 'F', 'age': 43} AssertionError: {'first_name': 'person', 'last_name': 'smith', 'sex': 'M', 'age': 1969} != {'first_name': 'person', 'last_name': 'smith', 'sex': 'M', 'age': 55}
I need the difference between the current year and the
year_of_birth
to get theage
I add an import statement
import datetime def factory( ...
then use it to get the current year for the age calculation
def factory( first_name, last_name, sex, year_of_birth ): return { 'first_name': first_name, 'last_name': last_name, 'sex': sex, 'age': datetime.datetime.today().year - year_of_birth, }
and the terminal shows TypeError
TypeError: factory() missing 2 required positional arguments: 'last_name' and 'sex'
I add a default value for
last_name
def factory( first_name, last_name=None, sex, year_of_birth ): ...
and get a SyntaxError
When I add a default value for
sex
def factory( first_name, last_name=None, sex=None, year_of_birth ): ...
the terminal shows the same SyntaxError
SyntaxError: parameter without a default follows parameter with a default
I add a default value for
year_of_birth
def factory( first_name, last_name=None, sex=None, year_of_birth=None ):
and the terminal shows AssertionError
AssertionError: {'first_name': 'person', 'last_name': None, 'sex': None, 'age': 76} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 76} AssertionError: {'first_name': 'john', 'last_name': None, 'sex': None, 'age': 101} != {'first_name': 'john', 'last_name': 'doe', 'sex': 'M', 'age': 101} AssertionError: {'first_name': 'joe', 'last_name': None, 'sex': None, 'age': 23} != {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 23} AssertionError: {'first_name': 'person', 'last_name': None, 'sex': None, 'age': 29} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 29}
the values for
last_name
andsex
do not match the expectationI change the default value for
last_name
def factory( first_name, last_name='doe', sex=None, year_of_birth=None ): ...
and get another AssertionError
AssertionError: {'first_name': 'john', 'last_name': 'doe', 'sex': None, 'age': 51} != {'first_name': 'john', 'last_name': 'doe', 'sex': 'M', 'age': 51} AssertionError: {'first_name': 'joe', 'last_name': 'doe', 'sex': None, 'age': 18} != {'first_name': 'joe', 'last_name': 'doe', 'sex': 'M', 'age': 18} AssertionError: {'first_name': 'person', 'last_name': 'doe', 'sex': None, 'age': 3} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 3} AssertionError: {'first_name': 'person', 'last_name': 'doe', 'sex': None, 'age': 67} != {'first_name': 'person', 'last_name': 'doe', 'sex': 'M', 'age': 67}
when I make the default value for
sex
match the expectationdef factory( first_name, last_name='doe', sex='M', year_of_birth=None ): ...
both tests pass!
review¶
I ran tests to make a function that takes in keyword arguments as input, has default values for some of them, performs an action based on an input and returns a dictionary as output
I also ran into the following Exceptions
Would you like to know how to test that an Exception is raised?