how to make a person with f-strings


Since I can pass objects to a string with f-strings, I can write one function that makes a person instead of one function for each person.


preview

I have these tests by the end of the chapter

person/tests/test_person.py
 1import src.person
 2
 3
 4def assert_say_hello_works(
 5        first_name, last_name,
 6        year_of_birth,
 7    ):
 8    reality = src.person.say_hello(
 9        first_name=first_name,
10        last_name=last_name,
11        year_of_birth=year_of_birth,
12    )
13    my_expectation = (
14        f'Hello, my name is {first_name}'
15        f' {last_name} and I am'
16        f' {2026-year_of_birth}.'
17    )
18    assert reality == my_expectation
person/tests/test_person.py
21def assert_person_factory_works(
22        first_name, last_name,
23        sex, year_of_birth
24    ):
25    reality = src.person.person(
26        first_name=first_name,
27        last_name=last_name,
28        sex=sex,
29        year_of_birth=year_of_birth,
30    )
31    my_expectation = (
32        f'{first_name}, {last_name},'
33        f' {sex}, {year_of_birth}'
34    )
35    assert reality == my_expectation
person/tests/test_person.py
38def test_joe():
39    first_name = 'joe'
40    last_name = 'blow'
41    sex = 'M'
42    year_of_birth = 1996
43
44    assert_person_factory_works(
45        first_name=first_name,
46        last_name=last_name,
47        sex=sex,
48        year_of_birth=year_of_birth,
49    )
50
51    assert_say_hello_works(
52        first_name=first_name,
53        last_name=last_name,
54        year_of_birth=year_of_birth,
55    )
person/tests/test_person.py
58def test_jane():
59    first_name = 'jane'
60    last_name = 'doe'
61    sex = 'F'
62    year_of_birth = 1991
63
64    assert_person_factory_works(
65        first_name=first_name,
66        last_name=last_name,
67        sex=sex,
68        year_of_birth=year_of_birth,
69    )
70
71    assert_say_hello_works(
72        first_name=first_name,
73        last_name=last_name,
74        year_of_birth=year_of_birth,
75    )
person/tests/test_person.py
78def test_john():
79    first_name = 'john'
80    last_name = 'smith'
81    sex = 'M'
82    year_of_birth = 1580
83
84    assert_person_factory_works(
85        first_name=first_name,
86        last_name=last_name,
87        sex=sex,
88        year_of_birth=year_of_birth,
89    )
90
91    assert_say_hello_works(
92        first_name=first_name,
93        last_name=last_name,
94        year_of_birth=year_of_birth,
95    )
person/tests/test_person.py
 98def test_mary():
 99    first_name = 'mary'
100    last_name = 'public'
101    sex = 'F'
102    year_of_birth = 2000
103
104    assert_person_factory_works(
105        first_name=first_name,
106        last_name=last_name,
107        sex=sex,
108        year_of_birth=year_of_birth,
109    )
110
111    assert_say_hello_works(
112        first_name=first_name,
113        last_name=last_name,
114        year_of_birth=year_of_birth,
115    )
116
117
118# Exceptions seen
119# AssertionError
120# NameError
121# TypeError
122# AttributeError

open the project

  • I open a terminal

  • I change directory to the project

    cd person
    

    the terminal shows I am in the person folder

    .../pumping_python/person
    
  • I open test_person.py from the tests folder

  • I use pytest-watcher to run the tests automatically

    uv run pytest-watcher . --now
    

    the terminal shows the tests from before are passing.


extract person function

RED: make it fail


I add an assertion to test_joe in tests/test_person.py

17  def test_joe():
18      assert joe() == 'joe, blow, M, 1996'
19
20      reality = person()
21      my_expectation = 'joe, blow, M, 1996'
22      assert reality == my_expectation
23
24
25  def test_jane():

the terminal is my friend, and shows NameError

NameError: name 'person' is not defined

because I have not defined person in tests/test_person.py, yet.


GREEN: make it pass


I add a function definition for it

1def person():
2    return 'joe, blow, M, 1996'
3
4
5def joe():

the test passes.

person() -> 'joe, blow, M, 1996'
└── def person():
    └── return 'joe, blow, M, 1996'

REFACTOR: make it better


  • I add an assertion with a call to the person function from test_jane

    21def test_joe():
    22    assert joe() == 'joe, blow, M, 1996'
    23
    24    reality = person()
    25    my_expectation = 'joe, blow, M, 1996'
    26    assert reality == my_expectation
    27
    28
    29def test_jane():
    30    assert jane() == 'jane, doe, F, 1991'
    31
    32    reality = person()
    33    my_expectation = 'jane, doe, F, 1991'
    34    assert reality == my_expectation
    35
    36
    37def test_john():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'joe, blow, M, 1996'
                        == 'jane, doe, F, 1991'
    

    because the person function always returns joe, blow, M, 1996 when it is called. I want it to return a string based on the input it gets for me to be able to use it to make more than one person.

  • I make the function take input for the first name

    1# def person():
    2def person(first_name):
    3    return 'joe, blow, M, 1996'
    

    the terminal is my friend, and shows TypeError

    TypeError: person() missing
               1 required positional argument:
               'first_name'
    

    because

  • I add 'jane' to the call to the person function from test_jane

    30def test_jane():
    31    assert jane() == 'jane, doe, F, 1991'
    32
    33    # reality = person()
    34    reality = person('jane')
    35    my_expectation = 'jane, doe, F, 1991'
    36    assert reality == my_expectation
    37
    38
    39def test_john():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'joe, blow, M, 1996'
                        == 'jane, doe, F, 1991'
    
  • I change the return statement of the person function to an f-string to use first_name in the output

    1# def person():
    2def person(first_name):
    3    # return 'joe, blow, M, 1996'
    4    return f'{first_name}, blow, M, 1996'
    5
    6
    7def joe():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'jane, blow, M, 1996'
                        == 'jane, doe, F, 1991'
    

    the first names match. Progress!

  • I add last_name to the return statement

     1# def person():
     2def person(first_name):
     3    # return 'joe, blow, M, 1996'
     4    # return f'{first_name}, blow, M, 1996'
     5    return (
     6        f'{first_name}, {last_name},'
     7        ' M, 1996'
     8    )
     9
    10
    11def joe():
    

    the terminal is my friend, and shows NameError

    NameError: name 'last_name' is not defined
    
  • I add the name to the parentheses to define it in the person function

     1# def person():
     2# def person(first_name):
     3def person(first_name, last_name):
     4    # return 'joe, blow, M, 1996'
     5    # return f'{first_name}, blow, M, 1996'
     6    return (
     7        f'{first_name}, {last_name},'
     8        ' M, 1996'
     9    )
    10
    11
    12def joe():
    

    the terminal is my friend, and shows TypeError

    TypeError: person() missing
               1 required positional argument:
               'last_name'
    

    because

  • I add 'doe' to the call to the person function in test_jane

    36def test_jane():
    37    assert jane() == 'jane, doe, F, 1991'
    38
    39    # reality = person()
    40    # reality = person('jane')
    41    reality = person('jane', 'doe')
    42    my_expectation = 'jane, doe, F, 1991'
    43    assert reality == my_expectation
    44
    45
    46def test_john():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'jane, doe, M, 1996'
                        == 'jane, doe, F, 1991'
    

    the first and last names match. More progress.

  • I change the call to the person function to use keyword arguments, then add a value for sex (since I have more than two arguments) in test_jane

    36def test_jane():
    37    assert jane() == 'jane, doe, F, 1991'
    38
    39    # reality = person()
    40    # reality = person('jane')
    41    # reality = person('jane', 'doe')
    42    reality = person(
    43        first_name='jane',
    44        last_name='doe',
    45        sex='F',
    46    )
    47    my_expectation = 'jane, doe, F, 1991'
    48    assert reality == my_expectation
    49
    50
    51def test_john():
    

    the terminal is my friend, and shows TypeError

    TypeError: person() got an unexpected
               keyword argument 'sex'
    

    because

  • I add sex in the parentheses of the person function definition

     1# def person():
     2# def person(first_name):
     3# def person(first_name, last_name):
     4def person(first_name, last_name, sex):
     5    # return 'joe, blow, M, 1996'
     6    # return f'{first_name}, blow, M, 1996'
     7    return (
     8        f'{first_name}, {last_name},'
     9        ' M, 1996'
    10    )
    11
    12
    13def joe():
    

    the terminal still shows AssertionError.

  • I add sex to the f-string in the person function

     1# def person():
     2# def person(first_name):
     3# def person(first_name, last_name):
     4def person(first_name, last_name, sex):
     5    # return 'joe, blow, M, 1996'
     6    # return f'{first_name}, blow, M, 1996'
     7    return (
     8        f'{first_name}, {last_name},'
     9        # ' M, 1996'
    10        f' {sex}, 1996'
    11    )
    12
    13
    14def joe():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'jane, doe, F, 1996'
                        == 'jane, doe, F, 1991'
    

    the first name, last name and sex match. Yes!

  • I add year_of_birth to the return statement

     1# def person():
     2# def person(first_name):
     3# def person(first_name, last_name):
     4def person(first_name, last_name, sex):
     5    # return 'joe, blow, M, 1996'
     6    # return f'{first_name}, blow, M, 1996'
     7    return (
     8        f'{first_name}, {last_name},'
     9        # ' M, 1996'
    10        # f' {sex}, 1996'
    11        f' {sex}, {year_of_birth}'
    12    )
    13
    14
    15def joe():
    

    the terminal is my friend, and shows NameError

    NameError: name 'year_of_birth' is not defined
    
  • I add year_of_birth to the parentheses to define it in the person function

     1# def person():
     2# def person(first_name):
     3# def person(first_name, last_name):
     4# def person(first_name, last_name, sex):
     5def person(
     6        first_name, last_name,
     7        sex, year_of_birth,
     8    ):
     9    # return 'joe, blow, M, 1996'
    10    # return f'{first_name}, blow, M, 1996'
    11    return (
    12        f'{first_name}, {last_name},'
    13        # ' M, 1996'
    14        # f'{sex}, 1996'
    15        f' {sex}, {year_of_birth}'
    16    )
    17
    18
    19def joe():
    

    the terminal is my friend, and shows TypeError

    TypeError: person() missing
               1 required positional argument:
               'year_of_birth'
    

    because

  • I add year_of_birth=1991 to the call to the person function from test_jane

    43def test_jane():
    44    assert jane() == 'jane, doe, F, 1991'
    45
    46    # reality = person()
    47    # reality = person('jane')
    48    # reality = person('jane', 'doe')
    49    reality = person(
    50        first_name='jane',
    51        last_name='doe',
    52        sex='F',
    53        year_of_birth=1991,
    54    )
    55    my_expectation = 'jane, doe, F, 1991'
    56    assert reality == my_expectation
    57
    58
    59def test_john():
    

    the terminal is my friend, and shows TypeError

    TypeError: person() missing
               4 required positional arguments:
               'first_name', 'last_name', 'sex',
               and 'year_of_birth'
    

    because

  • Since there are more than two arguments, I add keyword arguments to the call to the person function from test_joe

    35def test_joe():
    36    assert joe() == 'joe, blow, M, 1996'
    37
    38    # reality = person()
    39    reality = person(
    40        first_name='joe',
    41        last_name='blow',
    42        sex='M',
    43        year_of_birth=1996,
    44    )
    45    my_expectation = 'joe, blow, M, 1996'
    46    assert reality == my_expectation
    47
    48
    49def test_jane():
    

    the test passes. I have one function that I can use to make any number of people.

    person(
        first_name='joe', last_name='blow',
        sex='M', year_of_birth=1996,
    ) -> 'joe, blow, M, 1996'
    └── def person(
            first_name, last_name,
            sex, year_of_birth,
        ):
        ├── first_name    = 'joe'
        ├── last_name     = 'blow'
        ├── sex           = 'M'
        ├── year_of_birth = 1996
        └── return (
                f'{first_name}, {last_name},'
                f' {sex}, {year_of_birth}'
            )
            return 'joe, blow, M, 1996'
    
    person(
        first_name='jane', last_name='doe',
        sex='F', year_of_birth=1991,
    ) -> 'jane, doe, F, 1991'
    └── def person(
            first_name, last_name,
            sex, year_of_birth,
        ):
        ├── first_name    = 'jane'
        ├── last_name     = 'doe'
        ├── sex           = 'F'
        ├── year_of_birth = 1991
        └── return (
                f'{first_name}, {last_name},'
                f' {sex}, {year_of_birth}'
            )
            return 'jane, doe, F, 1991'
    

  • I remove the commented lines from the person function

     1def person(
     2        first_name, last_name,
     3        sex, year_of_birth,
     4    ):
     5    return (
     6        f'{first_name}, {last_name},'
     7        f' {sex}, {year_of_birth}'
     8    )
     9
    10
    11def joe():
    
  • I comment out the call to joe in test_joe because I no longer need it since the person function does the same thing

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29
    30    # reality = person()
    
  • I add a variable for 'joe' in test_joe

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30
    31    # reality = person()
    
  • I use the variable to remove repetition of 'joe'

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30
    31    # reality = person()
    32    reality = person(
    33        # first_name='joe',
    34        first_name=first_name,
    35        last_name='blow',
    36        sex='M',
    37        year_of_birth=1996,
    38    )
    39    # my_expectation = 'joe, blow, M, 1996'
    40    my_expectation = (
    41        f'{first_name}, blow, M, 1996'
    42    )
    43    assert reality == my_expectation
    44
    45
    46def test_jane():
    

    the test is still green.

  • I add a variable for 'blow' in test_joe

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30    last_name = 'blow'
    31
    32    # reality = person()
    
  • I use the variable to remove repetition of 'blow'

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30    last_name = 'blow'
    31
    32    # reality = person()
    33    reality = person(
    34        # first_name='joe',
    35        first_name=first_name,
    36        # last_name='blow',
    37        last_name=last_name,
    38        sex='M',
    39        year_of_birth=1996,
    40    )
    41    # my_expectation = 'joe, blow, M, 1996'
    42    my_expectation = (
    43        # f'{first_name}, blow,'
    44        f'{first_name}, {last_name},'
    45        ' M, 1996'
    46    )
    47    assert reality == my_expectation
    48
    49
    50def test_jane():
    

    still green.

  • I add a variable for 'M' in test_joe

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30    last_name = 'blow'
    31    sex = 'M'
    32
    33    # reality = person()
    
  • I use the variable to remove repetition of 'M' from test_joe

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30    last_name = 'blow'
    31    sex = 'M'
    32
    33    # reality = person()
    34    reality = person(
    35        # first_name='joe',
    36        first_name=first_name,
    37        # last_name='blow',
    38        last_name=last_name,
    39        # sex='M',
    40        sex=sex,
    41        year_of_birth=1996,
    42    )
    43    # my_expectation = 'joe, blow, M, 1996'
    44    my_expectation = (
    45        # f'{first_name}, blow,'
    46        f'{first_name}, {last_name},'
    47        # ' M, 1996'
    48        f' {sex}, 1996'
    49    )
    50    assert reality == my_expectation
    51
    52
    53def test_jane():
    

    green.

  • I add a variable for 1996 in test_joe

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30    last_name = 'blow'
    31    sex = 'M'
    32    year_of_birth = 1996
    33
    34    # reality = person()
    
  • I use the variable to remove repetition of 1996 from test_joe

    27def test_joe():
    28    # assert joe() == 'joe, blow, M, 1996'
    29    first_name = 'joe'
    30    last_name = 'blow'
    31    sex = 'M'
    32    year_of_birth = 1996
    33
    34    # reality = person()
    35    reality = person(
    36        # first_name='joe',
    37        first_name=first_name,
    38        # last_name='blow',
    39        last_name=last_name,
    40        # sex='M',
    41        sex=sex,
    42        # year_of_birth=1996,
    43        year_of_birth=year_of_birth,
    44    )
    45    # my_expectation = 'joe, blow, M, 1996'
    46    my_expectation = (
    47        # f'{first_name}, blow,'
    48        f'{first_name}, {last_name},'
    49        # ' M, 1996'
    50        # f' {sex}, 1996'
    51        f' {sex}, {year_of_birth}'
    52    )
    53    assert reality == my_expectation
    54
    55
    56def test_jane():
    

    still green.

  • I remove the commented lines from test_joe

    27def test_joe():
    28    first_name = 'joe'
    29    last_name = 'blow'
    30    sex = 'M'
    31    year_of_birth = 1996
    32
    33    reality = person(
    34        first_name=first_name,
    35        last_name=last_name,
    36        sex=sex,
    37        year_of_birth=year_of_birth,
    38    )
    39    my_expectation = (
    40        f'{first_name}, {last_name},'
    41        f' {sex}, {year_of_birth}'
    42    )
    43    assert reality == my_expectation
    44
    45
    46def test_jane():
    

  • I comment out the call to jane in test_jane because I no longer need it since the person function does the same thing

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48
    49    # reality = person()
    
  • I add a variable for 'jane' in test_jane

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49
    50    # reality = person()
    
  • I use the variable to remove repetition of 'jane'

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49
    50    # reality = person()
    51    # reality = person('jane')
    52    # reality = person('jane', 'doe')
    53    reality = person(
    54        # first_name='jane',
    55        first_name=first_name,
    56        last_name='doe',
    57        sex='F',
    58        year_of_birth=1991,
    59    )
    60    # my_expectation = 'jane, doe, F, 1991'
    61    my_expectation = (
    62        f'{first_name}, doe,'
    63        ' F, 1991'
    64    )
    65    assert reality == my_expectation
    66
    67
    68def test_john():
    

    the test is still green.

  • I add a variable for 'doe' in test_jane

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49    last_name = 'doe'
    50
    51    # reality = person()
    
  • I use the variable to remove repetition of 'doe'

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49    last_name = 'doe'
    50
    51    # reality = person()
    52    # reality = person('jane')
    53    # reality = person('jane', 'doe')
    54    reality = person(
    55        # first_name='jane',
    56        first_name=first_name,
    57        # last_name='doe',
    58        last_name=last_name,
    59        sex='F',
    60        year_of_birth=1991,
    61    )
    62    # my_expectation = 'jane, doe, F, 1991'
    63    my_expectation = (
    64        # f'{first_name}, doe,'
    65        f'{first_name}, {last_name},'
    66        ' F, 1991'
    67    )
    68    assert reality == my_expectation
    69
    70
    71def test_john():
    

    still green.

  • I add a variable for 'F' in test_jane

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49    last_name = 'doe'
    50    sex = 'F'
    51
    52    # reality = person()
    
  • I use the variable to remove repetition of 'F' from test_jane

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49    last_name = 'doe'
    50    sex = 'F'
    51
    52    # reality = person()
    53    # reality = person('jane')
    54    # reality = person('jane', 'doe')
    55    reality = person(
    56        # first_name='jane',
    57        first_name=first_name,
    58        # last_name='doe',
    59        last_name=last_name,
    60        # sex='F',
    61        sex=sex,
    62        year_of_birth=1991,
    63    )
    64    # my_expectation = 'jane, doe, F, 1991'
    65    my_expectation = (
    66        # f'{first_name}, doe,'
    67        f'{first_name}, {last_name},'
    68        # ' F, 1991'
    69        f' {sex}, 1991'
    70    )
    71    assert reality == my_expectation
    72
    73
    74def test_john():
    

    green.

  • I add a variable for 1991 in test_jane

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49    last_name = 'doe'
    50    sex = 'F'
    51    year_of_birth = 1991
    52
    53    # reality = person()
    
  • I use the variable to remove repetition of 1991

    46def test_jane():
    47    # assert jane() == 'jane, doe, F, 1991'
    48    first_name = 'jane'
    49    last_name = 'doe'
    50    sex = 'F'
    51    year_of_birth = 1991
    52
    53    # reality = person()
    54    # reality = person('jane')
    55    # reality = person('jane', 'doe')
    56    reality = person(
    57        # first_name='jane',
    58        first_name=first_name,
    59        # last_name='doe',
    60        last_name=last_name,
    61        # sex='F',
    62        sex=sex,
    63        # year_of_birth=1991,
    64        year_of_birth=year_of_birth,
    65    )
    66    # my_expectation = 'jane, doe, F, 1991'
    67    my_expectation = (
    68        # f'{first_name}, doe,'
    69        f'{first_name}, {last_name},'
    70        # ' F, 1991'
    71        # f' {sex}, 1991'
    72        f' {sex}, {year_of_birth}'
    73    )
    74    assert reality == my_expectation
    75
    76
    77def test_john():
    

    still green.

  • I remove the commented lines from test_jane

    46def test_jane():
    47    first_name = 'jane'
    48    last_name = 'doe'
    49    sex = 'F'
    50    year_of_birth = 1991
    51
    52    reality = person(
    53        first_name=first_name,
    54        last_name=last_name,
    55        sex=sex,
    56        year_of_birth=year_of_birth,
    57    )
    58    my_expectation = (
    59        f'{first_name}, {last_name},'
    60        f' {sex}, {year_of_birth}'
    61    )
    62    assert reality == my_expectation
    63
    64
    65def test_john():
    

  • I change the call in test_john to a call to the person function

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    reality = person(
    68        first_name='john',
    69        last_name='smith',
    70        sex='M',
    71        year_of_birth=1580,
    72    )
    73    my_expectation = 'jane, doe, F, 1991'
    74    assert reality == my_expectation
    75
    76
    77def test_mary():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'john, smith, M, 1580'
                        == 'jane, doe, F, 1991'
    
  • I change my_expectation to match reality

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    reality = person(
    68        first_name='john',
    69        last_name='smith',
    70        sex='M',
    71        year_of_birth=1580,
    72    )
    73    # my_expectation = 'jane, doe, F, 1991'
    74    my_expectation = 'john, smith, M, 1580'
    75    assert reality == my_expectation
    76
    77
    78def test_mary():
    

    the test passes.

    person(
        first_name='john', last_name='smith',
        sex='M', year_of_birth=1580,
    ) -> 'john, smith, M, 1580'
    └── def person(
            first_name, last_name,
            sex, year_of_birth,
        ):
        ├── first_name    = 'john'
        ├── last_name     = 'smith'
        ├── sex           = 'M'
        ├── year_of_birth = 1580
        └── return (
                f'{first_name}, {last_name},'
                f' {sex}, {year_of_birth}'
            )
            return 'john, smith, M, 1580'
    
  • I add a variable for 'john' in test_john

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68
    69    reality = person(
    70        first_name='john',
    71        last_name='smith',
    72        sex='M',
    73        year_of_birth=1580,
    74    )
    75    # my_expectation = 'jane, doe, F, 1991'
    76    my_expectation = 'john, smith, M, 1580'
    77    assert reality == my_expectation
    78
    79
    80def test_mary():
    
  • I use the variable to remove repetition of 'john'

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68
    69    reality = person(
    70        # first_name='john',
    71        first_name=first_name,
    72        last_name='smith',
    73        sex='M',
    74        year_of_birth=1580,
    75    )
    76    # my_expectation = 'jane, doe, F, 1991'
    77    # my_expectation = 'john, smith, M, 1580'
    78    my_expectation = (
    79        f'{first_name}, smith,'
    80        ' M, 1580'
    81    )
    82    assert reality == my_expectation
    83
    84
    85def test_mary():
    

    the test is still green.

  • I add a variable for 'smith' in test_john

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68    last_name = 'smith'
    
  • I use the variable to remove repetition of 'smith'

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68    last_name = 'smith'
    69
    70    reality = person(
    71        # first_name='john',
    72        first_name=first_name,
    73        # last_name='smith',
    74        last_name=last_name,
    75        sex='M',
    76        year_of_birth=1580,
    77    )
    78    # my_expectation = 'jane, doe, F, 1991'
    79    # my_expectation = 'john, smith, M, 1580'
    80    my_expectation = (
    81        # f'{first_name}, smith,'
    82        f'{first_name}, {last_name},'
    83        ' M, 1580'
    84    )
    85    assert reality == my_expectation
    86
    87
    88def test_mary():
    

    still green.

  • I add a variable for 'M' in test_john

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68    last_name = 'smith'
    69    sex = 'M'
    
  • I use the variable to remove repetition of 'M' from test_john

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68    last_name = 'smith'
    69    sex = 'M'
    70
    71    reality = person(
    72        # first_name='john',
    73        first_name=first_name,
    74        # last_name='smith',
    75        last_name=last_name,
    76        # sex='M',
    77        sex=sex,
    78        year_of_birth=1580,
    79    )
    80    # my_expectation = 'jane, doe, F, 1991'
    81    # my_expectation = 'john, smith, M, 1580'
    82    my_expectation = (
    83        # f'{first_name}, smith,'
    84        f'{first_name}, {last_name},'
    85        # ' M, 1580'
    86        f' {sex}, 1580'
    87    )
    88    assert reality == my_expectation
    89
    90
    91def test_mary():
    

    green.

  • I add a variable for 1580 in test_john

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68    last_name = 'smith'
    69    sex = 'M'
    70    year_of_birth = 1580
    
  • I use the variable to remove repetition of 1580

    65def test_john():
    66    # assert john() == 'john, smith, M, 1580'
    67    first_name = 'john'
    68    last_name = 'smith'
    69    sex = 'M'
    70    year_of_birth = 1580
    71
    72    reality = person(
    73        # first_name='john',
    74        first_name=first_name,
    75        # last_name='smith',
    76        last_name=last_name,
    77        # sex='M',
    78        sex=sex,
    79        # year_of_birth=1580,
    80        year_of_birth=year_of_birth,
    81    )
    82    # my_expectation = 'jane, doe, F, 1991'
    83    # my_expectation = 'john, smith, M, 1580'
    84    my_expectation = (
    85        # f'{first_name}, smith,'
    86        f'{first_name}, {last_name},'
    87        # ' M, 1580'
    88        # f' {sex}, 1580'
    89        f' {sex}, {year_of_birth}'
    90    )
    91    assert reality == my_expectation
    92
    93
    94def test_mary():
    

    still green.

  • I remove the commented lines from test_john

    65def test_john():
    66    first_name = 'john'
    67    last_name = 'smith'
    68    sex = 'M'
    69    year_of_birth = 1580
    70
    71    reality = person(
    72        first_name=first_name,
    73        last_name=last_name,
    74        sex=sex,
    75        year_of_birth=year_of_birth,
    76    )
    77    my_expectation = (
    78        f'{first_name}, {last_name},'
    79        f' {sex}, {year_of_birth}'
    80    )
    81    assert reality == my_expectation
    82
    83
    84def test_mary():
    
  • I make the same change to test_mary

     84def test_mary():
     85    # assert mary() == 'mary, public, F, 2000'
     86    first_name = 'mary'
     87    last_name = 'public'
     88    sex = 'F'
     89    year_of_birth = 2000
     90
     91    reality = person(
     92        first_name=first_name,
     93        last_name=last_name,
     94        sex=sex,
     95        year_of_birth=year_of_birth,
     96    )
     97    my_expectation = (
     98        f'{first_name}, {last_name},'
     99        f' {sex}, {year_of_birth}'
    100    )
    101    assert reality != my_expectation
    102
    103
    104# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'mary, public, F, 2000'
                        != 'mary, public, F, 2000'
    
  • I change the assertion

     97    my_expectation = (
     98        f'{first_name}, {last_name},'
     99        f' {sex}, {year_of_birth}'
    100    )
    101    # assert reality != my_expectation
    102    assert reality == my_expectation
    103
    104
    105# Exceptions seen
    

    the test passes.

    person(
        first_name='mary', last_name='public',
        sex='F', year_of_birth=2000,
    ) -> 'mary, public, F, 2000'
    └── def person(
            first_name, last_name,
            sex, year_of_birth,
        ):
        ├── first_name    = 'mary'
        ├── last_name     = 'public'
        ├── sex           = 'F'
        ├── year_of_birth = 2000
        └── return (
                f'{first_name}, {last_name},'
                f' {sex}, {year_of_birth}'
            )
            return 'mary, public, F, 2000'
    
  • I remove the commented lines from test_mary

     84def test_mary():
     85    first_name = 'mary'
     86    last_name = 'public'
     87    sex = 'F'
     88    year_of_birth = 2000
     89
     90    reality = person(
     91        first_name=first_name,
     92        last_name=last_name,
     93        sex=sex,
     94        year_of_birth=year_of_birth,
     95    )
     96    my_expectation = (
     97        f'{first_name}, {last_name},'
     98        f' {sex}, {year_of_birth}'
     99    )
    100    assert reality == my_expectation
    101
    102
    103# Exceptions seen
    
  • I remove the joe, jane, john and mary functions because they are no longer used

     1def person(
     2    first_name, last_name,
     3    sex, year_of_birth,
     4):
     5    return (
     6        f'{first_name}, {last_name},'
     7        f' {sex}, {year_of_birth}'
     8    )
     9
    10
    11def test_joe():
    

    the person function can make a string for any person I want when I give it the first name, last name, sex and year of birth.

  • I open a new terminal then change directories to person

    cd person
    
  • I add a git commit message in the new terminal

    git commit -am 'extract person function'
    

extract assert_person_factory_works function

test_joe, test_jane, test_john and test_mary are the same process, they

reality = person(
    first_name=first_name,
    last_name=last_name,
    sex=sex,
    year_of_birth=year_of_birth,
)
my_expectation = (
    f'{first_name}, {last_name},'
    f' {sex}, {year_of_birth}'
)
assert reality == my_expectation

I can make a function that takes in first_name, last_name, sex and year_of_birth then asserts that the result of the call to the person function with the variables is equal to the string with the values of the given parameters.


RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a new function to assert that the result of the call to the person function with the variables is equal to the string with the values of the given parameters

     1def person(
     2        first_name, last_name,
     3        sex, year_of_birth,
     4    ):
     5    return (
     6        f'{first_name}, {last_name},'
     7        f' {sex}, {year_of_birth}'
     8    )
     9
    10
    11def assert_person_factory_works(
    12        first_name, last_name,
    13        sex, year_of_birth,
    14    ):
    15    reality = person(
    16        first_name=first_name,
    17        last_name=last_name,
    18        sex=sex,
    19        year_of_birth=year_of_birth,
    20    )
    21    my_expectation = (
    22        f'{first_name}, {last_name},'
    23        f' {sex}, {year_of_birth}'
    24    )
    25    assert reality != my_expectation
    26
    27
    28def test_joe():
    
  • I use the assert_person_factory_works function in test_joe

    28def test_joe():
    29    first_name = 'joe'
    30    last_name = 'blow'
    31    sex = 'M'
    32    year_of_birth = 1996
    33
    34    # reality = person(
    35    #     first_name=first_name,
    36    #     last_name=last_name,
    37    #     sex=sex,
    38    #     year_of_birth=year_of_birth,
    39    # )
    40    # my_expectation = (
    41    #     f'{first_name}, {last_name},'
    42    #     f' {sex}, {year_of_birth}'
    43    # )
    44    # assert reality == my_expectation
    45    assert_person_factory_works(
    46        first_name=first_name,
    47        last_name=last_name,
    48        sex=sex,
    49        year_of_birth=year_of_birth,
    50    )
    51
    52
    53def test_jane():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'joe, blow, M, 1996'
                        != 'joe, blow, M, 1996'
    

GREEN: make it pass


I change the assertion in the assert_person_factory_works function

11def assert_person_factory_works(
12        first_name, last_name,
13        sex, year_of_birth,
14    ):
15    reality = person(
16        first_name=first_name,
17        last_name=last_name,
18        sex=sex,
19        year_of_birth=year_of_birth,
20    )
21    my_expectation = (
22        f'{first_name}, {last_name},'
23        f' {sex}, {year_of_birth}'
24    )
25    # assert reality != my_expectation
26    assert reality == my_expectation
27
28
29def test_joe():

the test passes.

assert_person_factory_works(
    first_name=first_name, last_name=last_name,
    sex=sex, year_of_birth=year_of_birth,
) -> None
└── def assert_person_factory_works(
        first_name, last_name,
        sex, year_of_birth,
    ):
    ├── reality = person(
           first_name=first_name,
           last_name=last_name,
           sex=sex,
           year_of_birth=year_of_birth,
       )
       └── def person(
               first_name, last_name,
               sex, year_of_birth,
           ):
           └── return (
                   f'{first_name}, {last_name},'
                   f' {sex}, {year_of_birth}'
               )
    ├── my_expectation = (
           f'{first_name}, {last_name},'
           f' {sex}, {year_of_birth}'
       )
    └── assert reality == my_expectation

REFACTOR: make it better


  • I remove the commented line from assert_person_factory_works

    11def assert_person_factory_works(
    12        first_name, last_name,
    13        sex, year_of_birth,
    14    ):
    15    reality = person(
    16        first_name=first_name,
    17        last_name=last_name,
    18        sex=sex,
    19        year_of_birth=year_of_birth,
    20    )
    21    my_expectation = (
    22        f'{first_name}, {last_name},'
    23        f' {sex}, {year_of_birth}'
    24    )
    25    assert reality == my_expectation
    26
    27
    28def test_joe():
    
  • I remove the commented lines from test_joe

    28def test_joe():
    29    first_name = 'joe'
    30    last_name = 'blow'
    31    sex = 'M'
    32    year_of_birth = 1996
    33
    34    assert_person_factory_works(
    35        first_name=first_name,
    36        last_name=last_name,
    37        sex=sex,
    38        year_of_birth=year_of_birth,
    39    )
    40
    41
    42def test_jane():
    
  • I use the assert_person_factory_works function in test_jane

    42def test_jane():
    43    first_name = 'jane'
    44    last_name = 'doe'
    45    sex = 'F'
    46    year_of_birth = 1991
    47
    48    # reality = person(
    49    #     first_name=first_name,
    50    #     last_name=last_name,
    51    #     sex=sex,
    52    #     year_of_birth=year_of_birth,
    53    # )
    54    # my_expectation = (
    55    #     f'{first_name}, {last_name},'
    56    #     f' {sex}, {year_of_birth}'
    57    # )
    58    # assert reality == my_expectation
    59    assert_person_factory_works(
    60        first_name=first_name,
    61        last_name=last_name,
    62        sex=sex,
    63        year_of_birth,
    64    )
    65
    66
    67def test_john():
    

    the test is still green.

  • I remove the commented lines from test_jane

    42def test_jane():
    43    first_name = 'jane'
    44    last_name = 'doe'
    45    sex = 'F'
    46    year_of_birth = 1991
    47
    48    assert_person_factory_works(
    49        first_name=first_name,
    50        last_name=last_name,
    51        sex=sex,
    52        year_of_birth,
    53    )
    54
    55
    56def test_john():
    
  • I use the assert_person_factory_works function in test_john

    56def test_john():
    57    first_name = 'john'
    58    last_name = 'smith'
    59    sex = 'M'
    60    year_of_birth = 1580
    61
    62    # reality = person(
    63    #     first_name=first_name,
    64    #     last_name=last_name,
    65    #     sex=sex,
    66    #     year_of_birth=year_of_birth,
    67    # )
    68    # my_expectation = (
    69    #     f'{first_name}, {last_name},'
    70    #     f' {sex}, {year_of_birth}'
    71    # )
    72    # assert reality == my_expectation
    73    assert_person_factory_works(
    74        first_name=first_name,
    75        last_name=last_name,
    76        sex=sex,
    77        year_of_birth=year_of_birth,
    78    )
    79
    80
    81def test_mary():
    

    still green.

  • I remove the commented lines from test_john

    56def test_john():
    57    first_name = 'john'
    58    last_name = 'smith'
    59    sex = 'M'
    60    year_of_birth = 1580
    61
    62    assert_person_factory_works(
    63        first_name=first_name,
    64        last_name=last_name,
    65        sex=sex,
    66        year_of_birth=year_of_birth,
    67    )
    68
    69
    70def test_mary():
    
  • I use the assert_person_factory_works function in test_mary

    70def test_mary():
    71    first_name = 'mary'
    72    last_name = 'public'
    73    sex = 'F'
    74    year_of_birth = 2000
    75
    76    # reality = person(
    77    #     first_name=first_name,
    78    #     last_name=last_name,
    79    #     sex=sex,
    80    #     year_of_birth=year_of_birth,
    81    # )
    82    # my_expectation = (
    83    #     f'{first_name}, {last_name},'
    84    #     f' {sex}, {year_of_birth}'
    85    # )
    86    # assert reality == my_expectation
    87    assert_person_factory_works(
    88        first_name=first_name,
    89        last_name=last_name,
    90        sex=sex,
    91        year_of_birth=year_of_birth,
    92    )
    93
    94
    95# Exceptions seen
    

    green.

  • I remove the commented lines from test_mary

    70def test_mary():
    71    first_name = 'mary'
    72    last_name = 'public'
    73    sex = 'F'
    74    year_of_birth = 2000
    75
    76    assert_person_factory_works(
    77        first_name=first_name,
    78        last_name=last_name,
    79        sex=sex,
    80        year_of_birth=year_of_birth,
    81    )
    82
    83
    84# Exceptions seen
    
  • I add a git commit message in the other terminal

    git commit -am \
    'extract assert_person_factory_works function'
    

separate and equal person

I want to move the person function to separate it from the tests.


RED: make it fail


  • I go back to the terminal where the tests are running

  • I change reality in the assert_person_factory_works function to be the result of a call to the person function of the person module in the src folder instead of a call to the person function in tests/test_person.py

    11def assert_person_factory_works(
    12        first_name, last_name,
    13        sex, year_of_birth,
    14    ):
    15    # reality = person(
    16    reality = src.person.person(
    17        first_name=first_name,
    18        last_name=last_name,
    19        sex=sex,
    20        year_of_birth=year_of_birth,
    21    )
    22    my_expectation = (
    23        f'{first_name}, {last_name},'
    24        f' {sex}, {year_of_birth}'
    25    )
    26    assert reality == my_expectation
    27
    28
    29def test_joe():
    

    the terminal is my friend, and shows NameError

    NameError: name 'src' is not defined
    

    because src is not defined in tests/test_person.py.


GREEN: make it pass


  • I add an import statement at the top of tests/test_person.py

    1import src.person
    2
    3
    4def person(
    5        first_name, last_name,
    6        sex, year_of_birth,
    7    ):
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.person'
                    has no attribute 'person'
    

    because there is nothing named person in the person module in the src folder.

  • I add AttributeError to the list of Exceptions seen

    88# Exceptions seen
    89# AssertionError
    90# NameError
    91# TypeError
    92# AttributeError
    
  • I open __init__.py from the person folder in the src folder

  • I delete all the text in the file then add a copy of the person function to src/person/__init__.py

    1def person(
    2        first_name, last_name,
    3        sex, year_of_birth,
    4    ):
    5    return (
    6        f'{first_name}, {last_name},'
    7        f' {sex}, {year_of_birth}'
    8    )
    

    all the tests are green again because

    • when import src.person runs Python brings in an object for the __init__.py file from the person folder in the src folder so I can use it in tests/test_person.py as src.person.

    • Python calls the person function from the object it imported for the src/person/__init__.py file (src.person) when src.person.person is called.

    I think of src.person.person like an address

    • person is something in __init__.py in the person folder, in this case it is a function in person

    • person is something in the src folder, in this case it is a folder in the src folder

    • src is something Python can import (a module, Python package or folder)

      src.person.person
      └── src/
          └── person/
              └── __init__.py
                  └── def person(
                          first_name, last_name,
                          sex, year_of_birth,
                      ):
                      └── return (
                              f'{first_name}, {last_name},'
                              f' {sex}, {year_of_birth}'
                          )
      

REFACTOR: make it better


  • I remove the commented line from assert_person_factory_works in tests/test_person.py

    14def assert_person_factory_works(
    15        first_name, last_name,
    16        sex, year_of_birth,
    17    ):
    18    reality = src.person.person(
    19        first_name=first_name,
    20        last_name=last_name,
    21        sex=sex,
    22        year_of_birth=year_of_birth,
    23    )
    24    my_expectation = (
    25        f'{first_name}, {last_name},'
    26        f' {sex}, {year_of_birth}'
    27    )
    28    assert reality == my_expectation
    29
    30
    31def test_joe():
    
  • I remove the person function from tests/test_person.py

     1import src.person
     2
     3
     4def test_joe():
     5    first_name = 'joe'
     6    last_name = 'blow'
     7    sex = 'M'
     8    year_of_birth = 1996
     9
    10    reality = src.person.person(
    11        first_name=first_name,
    12        last_name=last_name,
    13        sex=sex,
    14        year_of_birth=year_of_birth,
    15    )
    16    my_expectation = (
    17        f'{first_name}, {last_name},'
    18        f' {sex}, {year_of_birth}'
    19    )
    20    assert reality == my_expectation
    21
    22
    23def test_jane():
    

    all the tests are still green

  • I add a git commit message in the other terminal

    git commit -am \
    'move person function to src'
    

    the terminal shows a summary of the changes then goes back to the command line.

I can write solutions in a different module from the tests.


test say_hello function

I want the person I make to say hello. I can make a function that takes input for a person and returns a message.


RED: make it fail


  • I add an assertion to test_joe in tests/test_person.py

    21def test_joe():
    22    first_name = 'joe'
    23    last_name = 'blow'
    24    sex = 'M'
    25    year_of_birth = 1996
    26
    27    assert_person_factory_works(
    28        first_name=first_name,
    29        last_name=last_name,
    30        sex=sex,
    31        year_of_birth=year_of_birth,
    32    )
    33
    34    reality = say_hello(
    35        first_name=first_name,
    36        last_name=last_name,
    37        year_of_birth=year_of_birth,
    38    )
    39    my_expectation = (
    40        f'Hello, my name is {first_name}'
    41        f' {last_name} and I am'
    42        f' {2026-year_of_birth}.'
    43    )
    44    assert reality == my_expectation
    45
    46
    47def test_jane():
    

    the terminal is my friend, and shows NameError

    NameError: name 'say_hello' is not defined
    

GREEN: make it pass


  • I add a function definition for say_hello

     1import src.person
     2
     3
     4def say_hello():
     5    return None
     6
     7
     8def assert_person_factory_works(
     9        first_name, last_name,
    10        sex, year_of_birth,
    11    ):
    

    the terminal is my friend, and shows TypeError

    TypeError: say_hello() got an
               unexpected keyword argument
               'first_name'
    

    because

  • I add first_name in parentheses

    4# def say_hello():
    5def say_hello(first_name):
    6    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: say_hello()
               got an unexpected keyword argument 'last_name'.
               Did you mean 'first_name'?
    
  • I add last_name in parentheses

    4# def say_hello():
    5# def say_hello(first_name):
    6def say_hello(first_name, last_name):
    7    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: say_hello()
               got an unexpected keyword argument
               'year_of_birth'
    

    because the function definition (signature) of person only allows two arguments (first_name, last_name).

  • I add year_of_birth in parentheses

     4# def say_hello():
     5# def say_hello(first_name):
     6# def say_hello(first_name, last_name):
     7def say_hello(
     8        first_name, last_name,
     9        year_of_birth,
    10    ):
    11    return None
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None
        == 'Hello, my name is joe blow and I am 30.'
    
  • I change the return statement to give the test what it wants

     4# def say_hello():
     5# def say_hello(first_name):
     6# def say_hello(first_name, last_name):
     7def say_hello(
     8        first_name, last_name,
     9        year_of_birth,
    10    ):
    11    # return None
    12    return 'Hello, my name is joe blow and I am 30.'
    13
    14
    15def assert_person_factory_works(
    16        first_name, last_name,
    17        sex, year_of_birth,
    18    ):
    

    the test passes.

    ├── first_name = 'joe'
    ├── last_name = 'blow'
    ├── year_of_birth = 1996
    └── say_hello(
            first_name=first_name,
            last_name=last_name,
            year_of_birth=year_of_birth,
        ) -> 'Hello, my name is joe blow and I am 30.'
        └── def say_hello(
                first_name, last_name,
                year_of_birth,
            ):
            └── return 'Hello, my name is joe blow and I am 30.'
    

REFACTOR: make it better


  • I add an assertion for the say_hello function to test_jane

    58def test_jane():
    59    first_name = 'jane'
    60    last_name = 'doe'
    61    sex = 'F'
    62    year_of_birth = 1991
    63
    64    assert_person_factory_works(
    65        first_name=first_name,
    66        last_name=last_name,
    67        sex=sex,
    68        year_of_birth=year_of_birth,
    69    )
    70
    71    reality = say_hello(
    72        first_name=first_name,
    73        last_name=last_name,
    74        year_of_birth=year_of_birth,
    75    )
    76    my_expectation = (
    77        f'Hello, my name is {first_name}'
    78        f' {last_name} and I am'
    79        f' {2026-year_of_birth}.'
    80    )
    81    assert reality == my_expectation
    82
    83
    84def test_john():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'Hello, my name ... and I am 30.'
                        == 'Hello, my name ... and I am 35.'
    
  • I change the return statement of the say_hello function to an f-string to use first_name in the output

     4# def say_hello():
     5# def say_hello(first_name):
     6# def say_hello(first_name, last_name):
     7def say_hello(
     8        first_name, last_name,
     9        year_of_birth,
    10    ):
    11    # return None
    12    # return 'Hello, my name is joe blow and I am 30.'
    13    return (
    14        f'Hello, my name is {first_name}'
    15        ' blow and I am 30.'
    16    )
    

    the terminal shows AssertionError

    AssertionError: assert 'Hello, my name ... and I am 30.'
                        == 'Hello, my name ... and I am 35.'
    

    the first names now match and I still need better error messages.

  • I add last_name to the return statement

     4# def say_hello():
     5# def say_hello(first_name):
     6# def say_hello(first_name, last_name):
     7def say_hello(
     8        first_name, last_name,
     9        year_of_birth,
    10    ):
    11    # return None
    12    # return 'Hello, my name is joe blow and I am 30.'
    13    return (
    14        f'Hello, my name is {first_name}'
    15        # ' blow and I am 30.'
    16        f' {last_name} and I am 30.'
    17    )
    

    the terminal shows AssertionError

    AssertionError: assert 'Hello, my name ... and I am 30.'
                        == 'Hello, my name ... and I am 35.'
    

    the ages are different.

  • I add the age calculation to the return statement

     4# def say_hello():
     5# def say_hello(first_name):
     6# def say_hello(first_name, last_name):
     7def say_hello(
     8        first_name, last_name,
     9        year_of_birth,
    10    ):
    11    # return None
    12    # return 'Hello, my name is joe blow and I am 30.'
    13    age = 2026 - year_of_birth
    14
    15    return (
    16        f'Hello, my name is {first_name}'
    17        # ' blow and I am 30.'
    18        # f' {last_name} and I am 30.'
    19        f' {last_name} and I am {age}.'
    20    )
    

    the test passes.

    ├── first_name = 'jane'
    ├── last_name = 'doe'
    ├── year_of_birth = 1991
    └── say_hello(
            first_name=first_name,
            last_name=last_name,
            year_of_birth=year_of_birth,
        ) -> 'Hello, my name is jane doe and I am 35.'
        └── def say_hello(
                first_name, last_name,
                year_of_birth,
            ):
            ├── first_name    = 'jane'
            ├── last_name     = 'doe'
            ├── year_of_birth = 1991
            ├── age           = 2026 - year_of_birth
                             = 35
            └── return (
                    f'Hello, my name is {first_name}'
                    f' {last_name} and I am {age}.'
                )
                return 'Hello, my name is jane doe and I am 35.'
    
  • I remove the commented lines from the say_hello function

     1import src.person
     2
     3
     4def say_hello(
     5        first_name, last_name,
     6        year_of_birth,
     7    ):
     8    age = 2026 - year_of_birth
     9
    10    return (
    11        f'Hello, my name is {first_name}'
    12        f' {last_name} and I am {age}.'
    13    )
    14
    15
    16def assert_person_factory_works(
    17        first_name, last_name,
    18        sex, year_of_birth,
    19    ):
    
  • I add an assertion for the say_hello function to test_john in tests/test_person.py

     85def test_john():
     86    first_name = 'john'
     87    last_name = 'smith'
     88    sex = 'M'
     89    year_of_birth = 1580
     90
     91    assert_person_factory_works(
     92        first_name=first_name,
     93        last_name=last_name,
     94        sex=sex,
     95        year_of_birth=year_of_birth,
     96    )
     97
     98    reality = say_hello(
     99        first_name=first_name,
    100        last_name=last_name,
    101        year_of_birth=year_of_birth,
    102    )
    103    my_expectation = (
    104        'Hello, my name is jane'
    105        f' {last_name} and I am'
    106        f' {2026-year_of_birth}.'
    107    )
    108    assert reality == my_expectation
    109
    110
    111def test_mary():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'Hello, my name ...and I am 446.'
                        == 'Hello, my name ...and I am 446.'
    
  • I change my_expectation to match reality in test_john

    103    my_expectation = (
    104        # 'Hello, my name is jane'
    105        f'Hello, my name is {first_name}'
    106        f' {last_name} and I am'
    107        f' {2026-year_of_birth}.'
    108    )
    109    assert reality == my_expectation
    110
    111
    112def test_mary():
    

    the test passes.

    ├── first_name = 'john'
    ├── last_name = 'smith'
    ├── year_of_birth = 1580
    └── say_hello(
            first_name=first_name,
            last_name=last_name,
            year_of_birth=year_of_birth,
        ) -> 'Hello, my name is john smith and I am 446.'
        └── def say_hello(
                first_name, last_name,
                year_of_birth,
            ):
            ├── first_name    = 'john'
            ├── last_name     = 'smith'
            ├── year_of_birth = 1580
            ├── age           = 2026 - year_of_birth
                             = 446
            └── return (
                    f'Hello, my name is {first_name}'
                    f' {last_name} and I am {age}.'
                )
                return 'Hello, my name is john smith and I am 446.'
    
  • I add an assertion for the say_hello function to test_mary

    112def test_mary():
    113    first_name = 'mary'
    114    last_name = 'public'
    115    sex = 'F'
    116    year_of_birth = 2000
    117
    118    assert_person_factory_works(
    119        first_name=first_name,
    120        last_name=last_name,
    121        sex=sex,
    122        year_of_birth=year_of_birth,
    123    )
    124
    125    reality = say_hello(
    126        first_name=first_name,
    127        last_name=last_name,
    128        year_of_birth=year_of_birth,
    129    )
    130    my_expectation = (
    131        f'Hello, my name is {first_name}'
    132        ' smith and I am'
    133        f' {2026-year_of_birth}.'
    134    )
    135    assert reality == my_expectation
    136
    137
    138# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'Hello, my name ... and I am 26.'
                        == 'Hello, my name ... and I am 26.'
    
    • The last names are different.

    • I want better messages that show all of the differences in the summary.

  • I change my_expectation to match reality in test_mary

    130    my_expectation = (
    131        f'Hello, my name is {first_name}'
    132        # ' smith and I am'
    133        f' {last_name} and I am'
    134        f' {2026-year_of_birth}.'
    135    )
    136    assert reality == my_expectation
    137
    138
    139# Exceptions seen
    

    the test passes.

    ├── first_name = 'mary'
    ├── last_name = 'public'
    ├── year_of_birth = 2000
    └── say_hello(
            first_name=first_name,
            last_name=last_name,
            year_of_birth=year_of_birth,
        ) -> 'Hello, my name is mary public and I am 26.'
        └── def say_hello(
                first_name, last_name,
                year_of_birth,
            ):
            ├── first_name    = 'mary'
            ├── last_name     = 'public'
            ├── year_of_birth = 2000
            ├── age           = 2026 - year_of_birth
                             = 26
            └── return (
                    f'Hello, my name is {first_name}'
                    f' {last_name} and I am {age}.'
                )
                return 'Hello, my name is mary public and I am 26.'
    
  • I add a git commit message in the other terminal

    git commit -am 'test say_hello function'
    

extract assert_say_hello_works function

test_joe, test_jane, test_john and test_mary use the same process to test the say_hello function, they

reality = say_hello(
    first_name=first_name,
    last_name=last_name,
    year_of_birth=year_of_birth,
)
my_expectation = (
    f'Hello, my name is {first_name}'
    f' {last_name} and I am'
    f' {2026-year_of_birth}.'
)
assert reality == my_expectation

I can make a function that takes in first_name, last_name and year_of_birth then asserts that the result of the call to the say_hello function with the values is equal to the string with the values of the given parameters.


RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a new function to assert that the result of the call to the say_hello function with the variables is equal to the string with the values of the given parameters

     4def say_hello(
     5        first_name, last_name,
     6        year_of_birth,
     7    ):
     8    age = 2026 - year_of_birth
     9
    10    return (
    11        f'Hello, my name is {first_name}'
    12        f' {last_name} and I am {age}.'
    13    )
    14
    15
    16def assert_say_hello_works(
    17        first_name, last_name,
    18        year_of_birth,
    19    ):
    20    reality = say_hello(
    21        first_name=first_name,
    22        last_name=last_name,
    23        year_of_birth=year_of_birth,
    24    )
    25    my_expectation = (
    26        f'Hello, my name is {first_name}'
    27        f' {last_name} and I am'
    28        f' {2026-year_of_birth}.'
    29    )
    30    assert reality != my_expectation
    31
    32
    33def assert_say_hello_works(
    34        first_name, last_name,
    35        sex, year_of_birth,
    36    ):
    
  • I use the assert_say_hello_works function in test_joe

    50def test_joe():
    51    first_name = 'joe'
    52    last_name = 'blow'
    53    sex = 'M'
    54    year_of_birth = 1996
    55
    56    assert_person_factory_works(
    57        first_name=first_name,
    58        last_name=last_name,
    59        sex=sex,
    60        year_of_birth=year_of_birth,
    61    )
    62
    63    # reality = say_hello(
    64    #     first_name=first_name,
    65    #     last_name=last_name,
    66    #     year_of_birth=year_of_birth,
    67    # )
    68    # my_expectation = (
    69    #     f'Hello, my name is {first_name}'
    70    #     f' {last_name} and I am'
    71    #     f' {2026-year_of_birth}.'
    72    # )
    73    # assert reality == my_expectation
    74    assert_say_hello_works(
    75        first_name=first_name,
    76        last_name=last_name,
    77        year_of_birth=year_of_birth,
    78    )
    79
    80
    81def test_jane():
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'Hello, my name is joe blow and I am 30.'
                        != 'Hello, my name is joe blow and I am 30.'
    

GREEN: make it pass


I change the assertion in the assert_say_hello_works function

16def assert_say_hello_works(
17        first_name, last_name,
18        year_of_birth,
19    ):
20    reality = say_hello(
21        first_name=first_name,
22        last_name=last_name,
23        year_of_birth=year_of_birth,
24    )
25    my_expectation = (
26        f'Hello, my name is {first_name}'
27        f' {last_name} and I am'
28        f' {2026-year_of_birth}.'
29    )
30    # assert reality != my_expectation
31    assert reality == my_expectation
32
33
34def assert_person_factory_works(
35        first_name, last_name,
36        sex, year_of_birth,
37    ):

the test passes.

assert_say_hello_works(
    first_name=first_name,
    last_name=last_name,
    year_of_birth=year_of_birth,
) -> None
└── def assert_say_hello_works(
        first_name, last_name,
        sex, year_of_birth,
    ):
    ├── reality = say_hello(
           first_name=first_name,
           last_name=last_name,
           year_of_birth=year_of_birth,
       )
       └── def say_hello(
               first_name, last_name,
               year_of_birth,
           ):
           ├── age = 2026 - year_of_birth
           └── return (
                   f'Hello, my name is {first_name}'
                   f' {last_name} and I am {age}.'
               )
    ├── my_expectation = (
           f'Hello, my name is {first_name}'
           f' {last_name} and I am'
           f' {2026-year_of_birth}.'
       )
    └── assert reality == my_expectation

REFACTOR: make it better


  • I remove the commented line from assert_say_hello_works

    16def assert_say_hello_works(
    17        first_name, last_name,
    18        year_of_birth,
    19    ):
    20    reality = say_hello(
    21        first_name=first_name,
    22        last_name=last_name,
    23        year_of_birth=year_of_birth,
    24    )
    25    my_expectation = (
    26        f'Hello, my name is {first_name}'
    27        f' {last_name} and I am'
    28        f' {2026-year_of_birth}.'
    29    )
    30    assert reality == my_expectation
    31
    32
    33def assert_person_factory_works(
    34        first_name, last_name,
    35        sex, year_of_birth,
    36    ):
    
  • I remove the commented lines from test_joe

    50def test_joe():
    51    first_name = 'joe'
    52    last_name = 'blow'
    53    sex = 'M'
    54    year_of_birth = 1996
    55
    56    assert_person_factory_works(
    57        first_name=first_name,
    58        last_name=last_name,
    59        sex=sex,
    60        year_of_birth=year_of_birth,
    61    )
    62
    63    assert_say_hello_works(
    64        first_name=first_name,
    65        last_name=last_name,
    66        year_of_birth=year_of_birth,
    67    )
    68
    69
    70def test_jane():
    
  • I use the assert_say_hello_works function in test_jane

     70def test_jane():
     71    first_name = 'jane'
     72    last_name = 'doe'
     73    sex = 'F'
     74    year_of_birth = 1991
     75
     76    assert_person_factory_works(
     77        first_name=first_name,
     78        last_name=last_name,
     79        sex=sex,
     80        year_of_birth=year_of_birth,
     81    )
     82
     83    # reality = say_hello(
     84    #     first_name=first_name,
     85    #     last_name=last_name,
     86    #     year_of_birth=year_of_birth,
     87    # )
     88    # my_expectation = (
     89    #     f'Hello, my name is {first_name}'
     90    #     f' {last_name} and I am'
     91    #     f' {2026-year_of_birth}.'
     92    # )
     93    # assert reality == my_expectation
     94    assert_say_hello_works(
     95        first_name=first_name,
     96        last_name=last_name,
     97        year_of_birth=year_of_birth,
     98    )
     99
    100
    101def test_john():
    

    the test is still green.

  • I remove the commented lines from test_jane

    70def test_jane():
    71    first_name = 'jane'
    72    last_name = 'doe'
    73    sex = 'F'
    74    year_of_birth = 1991
    75
    76    assert_person_factory_works(
    77        first_name=first_name,
    78        last_name=last_name,
    79        sex=sex,
    80        year_of_birth=year_of_birth,
    81    )
    82
    83    assert_say_hello_works(
    84        first_name=first_name,
    85        last_name=last_name,
    86        year_of_birth=year_of_birth,
    87    )
    88
    89
    90def test_john():
    
  • I use the assert_say_hello_works function in test_john

     90def test_john():
     91    first_name = 'john'
     92    last_name = 'smith'
     93    sex = 'M'
     94    year_of_birth = 1580
     95
     96    assert_person_factory_works(
     97        first_name=first_name,
     98        last_name=last_name,
     99        sex=sex,
    100        year_of_birth=year_of_birth,
    101    )
    102
    103    # reality = say_hello(
    104    #     first_name=first_name,
    105    #     last_name=last_name,
    106    #     year_of_birth=year_of_birth,
    107    # )
    108    # my_expectation = (
    109    #     # f'Hello, my name is jane'
    110    #     f'Hello, my name is {first_name}'
    111    #     f' {last_name} and I am'
    112    #     f' {2026-year_of_birth}.'
    113    # )
    114    # assert reality == my_expectation
    115    assert_say_hello_works(
    116        first_name=first_name,
    117        last_name=last_name,
    118        year_of_birth=year_of_birth,
    119    )
    120
    121
    122def test_mary():
    

    still green.

  • I remove the commented lines from test_john

     90def test_john():
     91    first_name = 'john'
     92    last_name = 'smith'
     93    sex = 'M'
     94    year_of_birth = 1580
     95
     96    assert_person_factory_works(
     97        first_name=first_name,
     98        last_name=last_name,
     99        sex=sex,
    100        year_of_birth=year_of_birth,
    101    )
    102
    103    assert_say_hello_works(
    104        first_name=first_name,
    105        last_name=last_name,
    106        year_of_birth=year_of_birth,
    107    )
    108
    109
    110def test_mary():
    
  • I use the assert_say_hello_works function in test_mary

    110def test_mary():
    111    first_name = 'mary'
    112    last_name = 'public'
    113    sex = 'F'
    114    year_of_birth = 2000
    115
    116    assert_person_factory_works(
    117        first_name=first_name,
    118        last_name=last_name,
    119        sex=sex,
    120        year_of_birth=year_of_birth,
    121    )
    122
    123    # reality = say_hello(
    124    #     first_name=first_name,
    125    #     last_name=last_name,
    126    #     year_of_birth=year_of_birth,
    127    # )
    128    # my_expectation = (
    129    #     f'Hello, my name is {first_name}'
    130    #     # ' smith and I am'
    131    #     f' {last_name} and I am'
    132    #     f' {2026-year_of_birth}.'
    133    # )
    134    # assert reality == my_expectation
    135    assert_say_hello_works(
    136        first_name=first_name,
    137        last_name=last_name,
    138        year_of_birth=year_of_birth,
    139    )
    140
    141
    142# Exceptions seen
    

    green.

  • I remove the commented lines from test_mary

    110def test_mary():
    111    first_name = 'mary'
    112    last_name = 'public'
    113    sex = 'F'
    114    year_of_birth = 2000
    115
    116    assert_person_factory_works(
    117        first_name=first_name,
    118        last_name=last_name,
    119        sex=sex,
    120        year_of_birth=year_of_birth,
    121    )
    122
    123    assert_say_hello_works(
    124        first_name=first_name,
    125        last_name=last_name,
    126        year_of_birth=year_of_birth,
    127    )
    128
    129
    130# Exceptions seen
    131# AssertionError
    132# NameError
    133# TypeError
    134# AttributeError
    
  • I add a git commit message in the other terminal

    git commit -am \
    'extract assert_say_hello_works function'
    

separate and equal say_hello

I want to move the say_hello function to separate it from the tests.


RED: make it fail


  • I go back to the terminal where the tests are running

  • I change reality in the assert_say_hello_works function to be the result of a call to the say_hello function of the person module in the src folder instead of a call to the say_hello function in tests/test_person.py

    16def assert_say_hello_works(
    17        first_name, last_name,
    18        year_of_birth,
    19    ):
    20    # reality = say_hello(
    21    reality = src.person.say_hello(
    22        first_name=first_name,
    23        last_name=last_name,
    24        year_of_birth=year_of_birth,
    25    )
    26    my_expectation = (
    27        f'Hello, my name is {first_name}'
    28        f' {last_name} and I am'
    29        f' {2026-year_of_birth}.'
    30    )
    31    assert reality == my_expectation
    32
    33
    34def assert_person_factory_works(
    35        first_name, last_name,
    36        sex, year_of_birth,
    37    ):
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.person'
                    has no attribute 'say_hello'
    

    because there is nothing named say_hello in src/person/__init__.py.


GREEN: make it pass


I add a copy of the say_hello function to src/person/__init__.py

 1def person(
 2    first_name, last_name,
 3    sex, year_of_birth,
 4):
 5    return (
 6        f'{first_name}, {last_name},'
 7        f' {sex}, {year_of_birth}'
 8    )
 9
10
11def say_hello(
12    first_name, last_name,
13    year_of_birth,
14):
15    age = 2026 - year_of_birth
16
17    return (
18        f'Hello, my name is {first_name}'
19        f' {last_name} and I am {age}.'
20    )

the test passes.

src.person.say_hello
└── src/
    └── person/
        └── __init__.py
            └── def say_hello(
                    first_name, last_name,
                    year_of_birth,
                ):
                ├── age = 2026 - year_of_birth
                └── return (
                        f'Hello, my name is {first_name}'
                        f' {last_name} and I am {age}.'
                    )
  • I remove the commented line from assert_say_hello_works in tests/test_person.py

    16def assert_say_hello_works(
    17        first_name, last_name,
    18        year_of_birth,
    19    ):
    20    reality = src.person.say_hello(
    21        first_name=first_name,
    22        last_name=last_name,
    23        year_of_birth=year_of_birth,
    24    )
    25    my_expectation = (
    26        f'Hello, my name is {first_name}'
    27        f' {last_name} and I am'
    28        f' {2026-year_of_birth}.'
    29    )
    30    assert reality == my_expectation
    31
    32
    33def assert_person_factory_works(
    34        first_name, last_name,
    35        sex, year_of_birth,
    36    ):
    
  • I remove the say_hello function from tests/test_person.py

    1import src.person
    2
    3
    4def assert_say_hello_works(
    5        first_name, last_name,
    6        year_of_birth,
    7    ):
    

    all the tests are still green.

  • I add a git commit message in the other terminal

    git commit -am \
    'move say_hello function to src'
    

    the terminal shows a summary of the changes then goes back to the command line.


test_person

Since the solutions are separate from the tests, I can write the programs that make the tests pass without looking at tests/test_person.py.


RED: make it fail


  • I close tests/test_person.py

  • I delete all the text in src/person/__init__.py and the terminal shows AttributeError

    AttributeError: module 'src.person'
                    has no attribute 'person'
    

    Can you make the tests pass without looking at how I solve it below? You can come back to compare solutions when you are done or if you get stuck.


GREEN: make it pass


  • I add the name to src/person/__init__.py

    1person
    

    the terminal is my friend, and shows NameError

    NameError: name 'person' is not defined
    
  • I point person to None (the simplest object) to define it

    1# person
    2person = None
    

    the terminal is my friend, and shows TypeError

    TypeError: 'NoneType' object is not callable
    

    because person points to None and I cannot call None like a function.

  • I change person to a function to make it callable

    1# person
    2# person = None
    3def person():
    4    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: person() got
               an unexpected keyword argument
               'first_name'
    

    because this function definition does not allow any inputs, the parentheses are empty.

  • I add first_name in the parentheses so the function can take input

    1# person
    2# person = None
    3# def person():
    4def person(first_name):
    5    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: person() got
               an unexpected keyword argument 'last_name'.
               Did you mean 'first_name'?
    

    because the function definition now only allows one input (first_name) and it was called with a keyword argument (last_name).

  • I add last_name to the parentheses

    1# person
    2# person = None
    3# def person():
    4# def person(first_name):
    5def person(first_name, last_name):
    6    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: person() got
               an unexpected keyword argument 'sex'
    

    because the function definition only allows two inputs (first_name and last_name) and it was called with a keyword argument (sex).

  • I add sex to the parentheses

    1# person
    2# person = None
    3# def person():
    4# def person(first_name):
    5# def person(first_name, last_name):
    6def person(first_name, last_name, sex):
    7    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: person() got
               an unexpected keyword argument
               'year_of_birth'
    

    because the function definition only allows three inputs (first_name, last_name, sex) and it was called with a keyword argument (year_of_birth).

  • I add year_of_birth to the parentheses

     1# person
     2# person = None
     3# def person():
     4# def person(first_name):
     5# def person(first_name, last_name):
     6# def person(first_name, last_name, sex):
     7def person(
     8        first_name, last_name,
     9        sex, year_of_birth,
    10    ):
    11    return None
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == 'mary, public, F, 2000'
    
  • I change the return statement to match the expectation of the test

     1# person
     2# person = None
     3# def person():
     4# def person(first_name):
     5# def person(first_name, last_name):
     6# def person(first_name, last_name, sex):
     7def person(
     8        first_name, last_name,
     9        sex, year_of_birth,
    10    ):
    11    # return None
    12    return 'mary, public, F, 2000'
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.person'
                    has no attribute 'say_hello'
    
  • I add the name

     1say_hello
     2
     3
     4# person
     5# person = None
     6# def person():
     7# def person(first_name):
     8# def person(first_name, last_name):
     9# def person(first_name, last_name, sex):
    10def person(
    11        first_name, last_name,
    12        sex, year_of_birth,
    13    ):
    14    # return None
    15    return 'mary, public, F, 2000'
    

    the terminal is my friend, and shows NameError

    NameError: name 'say_hello' is not defined
    
  • I point it to None to define it

    1# say_hello
    2say_hello = None
    3
    4
    5# person
    

    the terminal is my friend, and shows TypeError

    TypeError: 'NoneType' object is not callable
    

    because say_hello points to None and I cannot call None like a function.

  • I make say_hello a function to make it callable

    1# say_hello
    2# say_hello = None
    3def say_hello():
    4    return None
    5
    6
    7# person
    

    the terminal is my friend, and shows TypeError

    TypeError: say_hello() got
               an unexpected keyword argument
               'first_name'
    

    because this function definition does not allow any inputs, the parentheses are empty.

  • I add first_name in the parentheses

    1# say_hello
    2# say_hello = None
    3# def say_hello():
    4def say_hello(first_name):
    5    return None
    6
    7
    8# person
    

    the terminal is my friend, and shows TypeError

    TypeError: say_hello() got
               an unexpected keyword argument 'last_name'.
               Did you mean 'first_name'?
    

    because the function definition now only allows one input (first_name) and it was called with a keyword argument (last_name).

  • I add last_name to the parentheses

    1# say_hello
    2# say_hello = None
    3# def say_hello():
    4# def say_hello(first_name):
    5def say_hello(first_name, last_name):
    6    return None
    7
    8
    9# person
    

    the terminal is my friend, and shows TypeError

    TypeError: say_hello() got
               an unexpected keyword argument
               'year_of_birth'
    

    because the function definition only allows two inputs (first_name and last_name) and it was called with a keyword argument (year_of_birth).

  • I add year_of_birth to the parentheses

     1# say_hello
     2# say_hello = None
     3# def say_hello():
     4# def say_hello(first_name):
     5# def say_hello(first_name, last_name):
     6def say_hello(
     7        first_name, last_name, year_of_birth,
     8    ):
     9    return None
    10
    11
    12# person
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None
        == 'Hello, my name is mary public and I am 26.'
    
  • I use ctrl/command+c (Windows & Linux/MacOS) on the keyboard to copy the string from the terminal and ctrl/command+v to paste it to replace None in the return statement

     1# say_hello
     2# say_hello = None
     3# def say_hello():
     4# def say_hello(first_name):
     5# def say_hello(first_name, last_name):
     6def say_hello(
     7        first_name, last_name, year_of_birth,
     8    ):
     9    # return None
    10    return 'Hello, my name is mary public and I am 26.'
    11
    12
    13# person
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'mary, public, F, 2000'
                        == 'john, smith, M, 1580'
    

    because the person function always returns 'mary, public, F, 2000' and this test expects 'john, smith, M, 1580'.

  • I change the return statement of the person function to see the difference between the input and the expected output (remember the identity function?)

    13# person
    14# person = None
    15# def person():
    16# def person(first_name):
    17# def person(first_name, last_name):
    18# def person(first_name, last_name, sex):
    19def person(
    20        first_name, last_name,
    21        sex, year_of_birth,
    22    ):
    23    # return None
    24    # return 'mary, public, F, 2000'
    25    return first_name, last_name, sex, year_of_birth,
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('mary', 'public', 'F', 2000)
                         == 'mary, public, F, 2000'
    

    the first_name, last_name, sex and year_of_birth are part of the output.

  • I change the return statement to an f-string with those values

    13# person
    14# person = None
    15# def person():
    16# def person(first_name):
    17# def person(first_name, last_name):
    18# def person(first_name, last_name, sex):
    19def person(
    20        first_name, last_name,
    21        sex, year_of_birth,
    22    ):
    23    # return None
    24    # return 'mary, public, F, 2000'
    25    # return first_name, last_name, sex, year_of_birth,
    26    return (
    27        f'{first_name}, {last_name},'
    28        f' {sex}, {year_of_birth}'
    29    )
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'Hello, my name ... and I am 26.'
                        == 'Hello, my name ...and I am 446.'
    

    because the say_hello function always returns 'Hello, my name is mary public and I am 26.' and this test expects 'Hello, my name is john smith and I am 446.'

  • I change the return statement of the say_hello function to see the difference between the input and the expected output

     1# say_hello
     2# say_hello = None
     3# def say_hello():
     4# def say_hello(first_name):
     5# def say_hello(first_name, last_name):
     6def say_hello(
     7        first_name, last_name, year_of_birth,
     8    ):
     9    # return None
    10    # return 'Hello, my name is mary public and I am 26.'
    11    return first_name, last_name, year_of_birth,
    12
    13
    14# person
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('mary', 'public', 'F', 2000)
                         == 'mary, public, F, 2000'
    

    the first_name and last_name are part of the output.

  • I change the return statement to an f-string with the input values

     1# say_hello
     2# say_hello = None
     3# def say_hello():
     4# def say_hello(first_name):
     5# def say_hello(first_name, last_name):
     6def say_hello(
     7        first_name, last_name, year_of_birth,
     8    ):
     9    # return None
    10    # return 'Hello, my name is mary public and I am 26.'
    11    # return first_name, last_name, year_of_birth,
    12    return (
    13        f'Hello, my name is {first_name}'
    14        f' {last_name} and I am {year_of_birth}.'
    15    )
    16
    17
    18# person
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert 'Hello, my name ...nd I am 2000.'
                        == 'Hello, my name ... and I am 26.'
    

    It looks like 26 is the age.

  • I change the year_of_birth value to a calculation of the age

     1# say_hello
     2# say_hello = None
     3# def say_hello():
     4# def say_hello(first_name):
     5# def say_hello(first_name, last_name):
     6def say_hello(
     7        first_name, last_name, year_of_birth,
     8    ):
     9    # return None
    10    # return 'Hello, my name is mary public and I am 26.'
    11    # return first_name, last_name, year_of_birth,
    12    return (
    13        f'Hello, my name is {first_name}'
    14        # f' {last_name} and I am {year_of_birth}.'
    15        f' {last_name} and I am'
    16        f' {2026-year_of_birth}.'
    17    )
    18
    19
    20# person
    

    all the tests are green!

  • I remove the commented lines from src/person/__init__.py

     1def say_hello(
     2        first_name, last_name, year_of_birth,
     3    ):
     4    return (
     5        f'Hello, my name is {first_name}'
     6        f' {last_name} and I am'
     7        f' {2026-year_of_birth}.'
     8    )
     9
    10
    11def person(
    12        first_name, last_name,
    13        sex, year_of_birth,
    14    ):
    15    return (
    16        f'{first_name}, {last_name},'
    17        f' {sex}, {year_of_birth}'
    18    )
    
  • I add a git commit message in the new terminal

    git commit -am 'test person with f-strings'
    

close the project

  • I close src/person/__init__.py

  • I click in the terminal where the tests are running

  • I use q on the keyboard to leave the tests. The terminal goes back to the command line.

  • I change directory to the parent of person

    cd ..
    

    the terminal shows

    ...\pumping_python
    

    I am back in the pumping_python directory.


review

  • I ran tests to write one function that makes a string for a person when given first_name, last_name, sex and year_of_birth so I do not have to make one function for each person.

  • I also ran tests to make another function that makes an f-string to represent the person saying hello when I give it first_name, last_name, and year_of_birth.

  • My tests and solutions have a few problems,

For now, I am going to clean up the functions project so the tests and solutions are in separate files.


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

Would you like to test making a person with a class?


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.