test functions with generators

I want to use for loops in the functions project.


preview

I have these tests by the end of the chapter

functions/tests/test_functions.py
 1import src.functions
 2import unittest
 3
 4
 5class TestFunctions(unittest.TestCase):
 6
 7    first = 'first'
 8    last = 'last'
 9    a_tuple = (0, 1, 2, 'n')
10    a_list = [0, 1, 2, 'n']
11    a_set = {0, 1, 2, 'n'}
12    a_dictionary = {'key': 'value'}
functions/tests/test_functions.py
14    def test_functions_return_none_by_default(self):
15        for a_function in (
16            src.functions.w_pass,
17            src.functions.w_return,
18            src.functions.w_return_none,
19            src.functions.return_leaves_the_function,
20        ):
21            with self.subTest(a_function):
22                self.assertIsNone(a_function())
23
24    def test_constant_function(self):
25        self.assertEqual(
26            src.functions.constant(), 'the same thing'
27        )
functions/tests/test_functions.py
29    def test_identity_function(self):
30        for an_object in (
31            None, object, self.first, self.last,
32            self.a_tuple, self.a_list,
33            self.a_set, self.a_dictionary,
34        ):
35            with self.subTest(an_object):
36                self.assertEqual(
37                    src.functions.identity(an_object),
38                    an_object
39                )
functions/tests/test_functions.py
41    def test_why_use_a_for_loop(self):
42        def add_x(number):
43            return 3 + number
44
45        for a_number in range(1000):
46            with self.subTest(a_number):
47                self.assertEqual(
48                    add_x(a_number), a_number+3
49                )
functions/tests/test_functions.py
51    def test_args_and_kwargs(self):
52        for first, second in (
53            (self.first, self.last),
54            (self.last, self.first),
55            (0, 1),
56            (self.a_tuple, self.a_list),
57            (self.a_set, self.a_dictionary),
58        ):
59            for a_function in (
60                src.functions.positional_arguments,
61                src.functions.keyword_arguments,
62                src.functions.args_and_kwargs,
63                src.functions.optional_arguments,
64            ):
65                with self.subTest(
66                    a_function=a_function, inputs=(first, second)
67                ):
68                    self.assertEqual(
69                        a_function(first, second),
70                        (first, second)
71                    )
72                    self.assertEqual(
73                        a_function(
74                            last_input=first,
75                            first_input=second,
76                        ),
77                        (second, first)
78                    )
79                    self.assertEqual(
80                        a_function(
81                            first, last_input=second,
82                        ),
83                        (first, second)
84                    )
85                    self.assertEqual(
86                        a_function(
87                            second, last_input=first,
88                        ),
89                        (second, first)
90                    )

open the project

  • I open a terminal

  • I change directory to the project

    terminal
    cd functions
    
  • I open test_functions.py from the tests folder

  • I use pytest-watcher to run the tests automatically

    terminal
    uv run pytest-watcher . --now --patterns "**/*.py"
    

extract test_functions_return_none_by_default

test_making_a_function_w_pass, test_making_a_function_w_return, test_making_a_function_w_return_none and test_what_happens_after_functions_return all assert that a function returns None by default

self.assertIsNone(function())

I can make a function with a for loop to remove the repetition.


RED: make it fail


I add a test with a for loop for what a function returns by default

functions/tests/test_functions.py
10      a_list = [0, 1, 2, 'n']
11      a_set = {0, 1, 2, 'n'}
12      a_dictionary = {'key': 'value'}
13
14      def test_functions_return_none_by_default(self):
15          for a_function in (
16              src.functions.w_pass,
17              src.functions.w_return,
18              src.functions.w_return_none,
19              src.functions.return_leaves_the_function,
20          ):
21              with self.subTest(a_function):
22                  self.assertIsNotNone(a_function())
23
24      def test_making_a_function_w_pass(self):

the terminal is my friend, and shows AssertionError

terminal
SUBFAILED[<function w_pass at 0xffffa0b12345>] ...
    AssertionError: unexpectedly None
SUBFAILED[<function w_return at 0xffffc6d78012>] ...
    AssertionError: unexpectedly None
SUBFAILED[<function w_return_none at 0xffffe3f45678>] ...
    AssertionError: unexpectedly None
SUBFAILED[<function return_leaves_the_function at 0xffffa01234b5>] ...
    AssertionError: unexpectedly None

GREEN: make it pass


I change assertIsNotNone to assertIsNone

functions/tests/test_functions.py
21            with self.subTest(a_function):
22                self.assertIsNone(a_function())
23
24    def test_making_a_function_w_pass(self):

the test passes


REFACTOR: make it better



test_identity_function with a loop

RED: make it fail


I add a for loop to test_identity_function

functions/tests/test_functions.py
29    def test_identity_function(self):
30        for an_object in (
31            None, object, self.first, self.last,
32            self.a_tuple, self.a_list,
33            self.a_set, self.a_dictionary,
34        ):
35            with self.subTest(an_object):
36                self.assertNotEqual(
37                    src.functions.identity(an_object),
38                    an_object
39                )
40
41        self.assertIsNone(src.functions.identity(None))
42        self.assertEqual(
43            src.functions.identity(object), object
44        )
45
46    def test_why_use_a_function(self):

the terminal is my friend, and shows AssertionError

terminal
SUBFAILED[None] ...AssertionError: None == None
SUBFAILED[<class 'object'>] ...
    AssertionError: <class 'object'> == <class 'object'>
SUBFAILED[first] ...AssertionError: 'first' == 'first'
SUBFAILED[last] ...AssertionError: 'last' == 'last'
SUBFAILED[(0, 1, 2, 'n')] ...
    AssertionError: (0, 1, 2, 'n') == (0, 1, 2, 'n')
SUBFAILED[[0, 1, 2, 'n']] ...
    AssertionError: [0, 1, 2, 'n'] == [0, 1, 2, 'n']
SUBFAILED[{0, 1, 2, 'n'}] ...
    AssertionError: {0, 1, 2, 'n'} == {0, 1, 2, 'n'}
SUBFAILED[{'key': 'value'}] ...
    AssertionError: {'key': 'value'} == {'key': 'value'}

GREEN: make it pass


I change assertNotEqual to assertEqual

functions/tests/test_functions.py
35            with self.subTest(an_object):
36                self.assertEqual(
37                    src.functions.identity(an_object),
38                    an_object
39                )
40
41        self.assertIsNone(src.functions.identity(None))

the test passes.


REFACTOR: make it better


  • I remove the other assertions from test_identity_function because they are now covered by the for loop

    functions/tests/test_functions.py
    29    def test_identity_function(self):
    30        for an_object in (
    31            None, object, self.first, self.last,
    32            self.a_tuple, self.a_list,
    33            self.a_set, self.a_dictionary,
    34        ):
    35            with self.subTest(an_object):
    36                self.assertEqual(
    37                    src.functions.identity(an_object),
    38                    an_object
    39                )
    40
    41    def test_why_use_a_function(self):
    
  • I add a git commit message

    terminal
    git commit -am \
    'test_identity_function with a for loop'
    

test_why_use_a_for_loop

test_why_use_a_function makes ten assertions that all look the same

self.assertEqual(add_x(a_number), result)

I can use a for loop to remove the repetition


RED: make it fail


I add a for loop to test_why_use_a_function

functions/tests/test_functions.py
41    def test_why_use_a_function(self):
42        def add_x(number):
43            return 3 + number
44
45        for a_number in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9):
46            with self.subTest(a_number):
47                self.assertEqual(add_x(a_number), 'BOOM!!!')
48
49        self.assertEqual(add_x(0), 3)
50        self.assertEqual(add_x(1), 4)
51        self.assertEqual(add_x(2), 5)

the terminal is my friend, and shows AssertionError

terminal
SUBFAILED[0] ...AssertionError: 3 != 'BOOM!!!'
SUBFAILED[1] ...AssertionError: 4 != 'BOOM!!!'
SUBFAILED[2] ...AssertionError: 5 != 'BOOM!!!'
SUBFAILED[3] ...AssertionError: 6 != 'BOOM!!!'
SUBFAILED[4] ...AssertionError: 7 != 'BOOM!!!'
SUBFAILED[5] ...AssertionError: 8 != 'BOOM!!!'
SUBFAILED[6] ...AssertionError: 9 != 'BOOM!!!'
SUBFAILED[7] ...AssertionError: 10 != 'BOOM!!!'
SUBFAILED[8] ...AssertionError: 11 != 'BOOM!!!'
SUBFAILED[9] ...AssertionError: 12 != 'BOOM!!!'

GREEN: make it pass


I change self.assertEqual(add_x(a_number), 'BOOM!!!')

functions/tests/test_functions.py
45        for a_number in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9):
46            with self.subTest(a_number):
47                self.assertEqual(
48                    add_x(a_number), a_number+3
49                )
50
51        self.assertEqual(add_x(0), 3)

the test passes.


REFACTOR: make it better


  • I remove the other assertions from test_why_use_a_function because they are now covered by the for loop

    functions/tests/test_functions.py
    41    def test_why_use_a_function(self):
    42        def add_x(number):
    43            return 3 + number
    44
    45        for a_number in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9):
    46            with self.subTest(a_number):
    47                self.assertEqual(
    48                    add_x(a_number), a_number+3
    49                )
    50
    51    def test_positional_arguments(self):
    

the range object

Python has an iterable I can use to make a sequence of numbers, it is called the range object.

range(0, a_number) makes a range object that goes from the first number in the parentheses to the second number minus 1

  • I change the tuple in the for loop to a range object

    functions/tests/test_functions.py
    41    def test_why_use_a_function(self):
    42        def add_x(number):
    43            return 3 + number
    44
    45        for a_number in range(0, 10):
    46            with self.subTest(a_number):
    47                self.assertNotEqual(
    48                    add_x(a_number), a_number+3
    49                )
    50
    51    def test_positional_arguments(self):
    

    the terminal is my friend, and shows AssertionError

    terminal
    SUBFAILED[0] ...AssertionError: 3 == 3
    SUBFAILED[1] ...AssertionError: 4 == 4
    SUBFAILED[2] ...AssertionError: 5 == 5
    SUBFAILED[3] ...AssertionError: 6 == 6
    SUBFAILED[4] ...AssertionError: 7 == 7
    SUBFAILED[5] ...AssertionError: 8 == 8
    SUBFAILED[6] ...AssertionError: 9 == 9
    SUBFAILED[7] ...AssertionError: 10 == 10
    SUBFAILED[8] ...AssertionError: 11 == 11
    SUBFAILED[9] ...AssertionError: 12 == 12
    
  • I can remove the 0 from the range object

    functions/tests/test_functions.py
    45        for a_number in range(10):
    

    the AssertionError stays the same.

  • I can use any number I want

    functions/tests/test_functions.py
    45        for a_number in range(1000):
    

    the terminal shows AssertionError for one thousand sub tests and my tests run slower than before. What would happen if I changed the number to one million?

  • I change assertNotEqual to assertEqual

    functions/tests/test_functions.py
    41    def test_why_use_a_function(self):
    42        def add_x(number):
    43            return 3 + number
    44
    45        for a_number in range(1000):
    46            with self.subTest(a_number):
    47                self.assertEqual(
    48                    add_x(a_number), a_number+3
    49                )
    50
    51    def test_positional_arguments(self):
    

    the test passes.

  • I change the name of the test from test_why_use_a_function to test_why_use_a_for_loop

    functions/tests/test_functions.py
    35            with self.subTest(an_object):
    36                self.assertEqual(
    37                    src.functions.identity(an_object),
    38                    an_object
    39                )
    40
    41    def test_why_use_a_for_loop(self):
    42        def add_x(number):
    43            return 3 + number
    
  • I add a git commit message

    terminal
    git commit -am \
    'rename to test_why_use_a_for_loop'
    

test_positional_arguments with for loops

test_positional_arguments has assertions that check what happens when a function is called with positional arguments

self.assertEqual(
    function(position_0, position_1),
    (position_0, position_1)
)

I can use a for loop to remove repetition from the test.


RED: make it fail


I add a for loop for each one of the arguments used

functions/tests/test_functions.py
51    def test_positional_arguments(self):
52        for first, second in (
53            (self.first, self.last),
54            (self.last, self.first),
55            (0, 1),
56            (self.a_tuple, self.a_list),
57            (self.a_set, self.a_dictionary),
58        ):
59            with self.subTest(inputs=(first, second)):
60                self.assertEqual(
61                    src.functions.positional_arguments(
62                        first, second
63                    ),
64                    (second, first)
65                )
66
67        positional_arguments = (
68            src.functions.positional_arguments
69        )

the terminal is my friend, and shows AssertionError

terminal
SUBFAILED(inputs=('first', 'last')) ...
    AssertionError: Tuples differ:
        ('first', 'last') != ('last', 'first')
SUBFAILED(inputs=('last', 'first')) ...
    AssertionError: Tuples differ:
        ('last', 'first') != ('first', 'last')
SUBFAILED(inputs=(0, 1)) ...
    AssertionError: Tuples differ:
        (0, 1) != (1, 0)
SUBFAILED(inputs=((0, 1, 2, 'n'), [0, 1, 2, 'n'])) ...
    AssertionError: Tuples differ:
        ((0, 1, 2, 'n'), [0, 1, 2, 'n'])
    !=  ([0, 1, 2, 'n'], (0, 1, 2, 'n'))
SUBFAILED(inputs=({0, 1, 2, 'n'}, {'key': 'value'})) ...
    AssertionError: Tuples differ:
        ({0, 1, 2, 'n'}, {'key': 'value'})
     != ({'key': 'value'}, {0, 1, 2, 'n'})

GREEN: make it pass


I change the expectation of the assertion in test_positional_arguments

functions/tests/test_functions.py
59            with self.subTest(inputs=(first, second)):
60                self.assertEqual(
61                    src.functions.positional_arguments(
62                        first, second
63                    ),
64                    (first, second)
65                )
66
67the test passes.

REFACTOR: make it better


  • I add a for loop with calls to the positional_arguments, keyword_arguments, args_and_kwargs and optional_arguments functions

    functions/tests/test_functions.py
    51    def test_positional_arguments(self):
    52        for first, second in (
    53            (self.first, self.last),
    54            (self.last, self.first),
    55            (0, 1),
    56            (self.a_tuple, self.a_list),
    57            (self.a_set, self.a_dictionary),
    58        ):
    59            for a_function in (
    60                src.functions.positional_arguments,
    61                src.functions.keyword_arguments,
    62                src.functions.args_and_kwargs,
    63                src.functions.optional_arguments,
    64            ):
    
    functions/tests/test_functions.py
    65                with self.subTest(
    66                    a_function=a_function, inputs=(first, second)
    67                ):
    68                    self.assertEqual(
    69                        a_function(first, second),
    70                        (second, first)
    71                    )
    72
    73        positional_arguments = (
    74            src.functions.positional_arguments
    75        )
    

    the terminal is my friend, and shows AssertionError for twenty sub tests.

  • I change the expectation of the assertion in test_positional_arguments

    functions/tests/test_functions.py
    68                    self.assertEqual(
    69                        a_function(first, second),
    70                        (first, second)
    71                    )
    72
    73        positional_arguments = (
    74            src.functions.positional_arguments
    75        )
    

    the test passes.

  • I remove the other statements from test_positional_arguments because they are now covered by the for loop

    functions/tests/test_functions.py
    68                    self.assertEqual(
    69                        a_function(first, second),
    70                        (first, second)
    71                    )
    72
    73    def test_keyword_arguments(self):
    
  • I add a git commit message

    terminal
    git commit -am \
    'test_positional_arguments with for loops'
    

test_keyword_arguments with for loops

test_keyword_arguments has assertions that check what happens when a function is called with keyword arguments

self.assertEqual(
    function(
        last_input=something,
        first_input=something_else),
    (something_else, something)
)

I can use a for loop to remove repetition from the test.


RED: make it fail


I add a for loop for each one of the arguments and the positional_arguments, keyword_arguments and optional_arguments functions because they all have the same signature

functions/tests/test_functions.py
73    def test_keyword_arguments(self):
74        for first, second in (
75            (self.first, self.last),
76            (self.last, self.first),
77            (0, 1),
78            (self.a_tuple, self.a_list),
79            (self.a_set, self.a_dictionary),
80        ):
81            for a_function in (
82                src.functions.positional_arguments,
83                src.functions.keyword_arguments,
84                src.functions.optional_arguments,
85            ):
functions/tests/test_functions.py
86                with self.subTest(
87                    a_function=a_function, inputs=(first, second)
88                ):
89                    self.assertEqual(
90                        a_function(
91                            last_input=first,
92                            first_input=second,
93                        ),
94                        (first, second)
95                    )
96
97        keyword_arguments = (
98            src.functions.keyword_arguments
99        )

the terminal is my friend, and shows AssertionError for fifteen sub tests.


GREEN: make it pass


I change the expectation of the assertion in test_keyword_arguments

functions/tests/test_functions.py
89                    self.assertEqual(
90                        a_function(
91                            last_input=first,
92                            first_input=second,
93                        ),
94                        (second, first)
95                    )
96
97        keyword_arguments = (
98            src.functions.keyword_arguments
99        )

the test passes.


REFACTOR: make it better


  • I add the args_and_kwargs function to the for loop

    functions/tests/test_functions.py
    73    def test_keyword_arguments(self):
    74        for first, second in (
    75            (self.first, self.last),
    76            (self.last, self.first),
    77            (0, 1),
    78            (self.a_tuple, self.a_list),
    79            (self.a_set, self.a_dictionary),
    80        ):
    81            for a_function in (
    82                src.functions.positional_arguments,
    83                src.functions.keyword_arguments,
    84                src.functions.args_and_kwargs,
    85                src.functions.optional_arguments,
    86            ):
    

    the terminal is my friend, and shows TypeError

    terminal
    SUBFAILED(
        a_function=<function args_and_kwargs at 0xffff01ab2c34>,
        inputs=('first', 'last')
    ) ...TypeError: args_and_kwargs()
                    got an unexpected keyword argument 'first_input'.
                    Did you mean 'last_input'?
    SUBFAILED(
        a_function=<function args_and_kwargs at 0xffff01ab2c34>,
        inputs=('last', 'first')
    ) ...TypeError: args_and_kwargs()
                    got an unexpected keyword argument 'first_input'.
                    Did you mean 'last_input'?
    SUBFAILED(
        a_function=<function args_and_kwargs at 0xffff01ab2c34>,
        inputs=(0, 1)
    ) ...TypeError: args_and_kwargs()
                    got an unexpected keyword argument 'first_input'.
                    Did you mean 'last_input'?
    SUBFAILED(
        a_function=<function args_and_kwargs at 0xffff01ab2c34>,
        inputs=((0, 1, 2, 'n'), [0, 1, 2, 'n'])
    ) ...TypeError: args_and_kwargs()
                    got an unexpected keyword argument 'first_input'.
                    Did you mean 'last_input'?
    SUBFAILED(
        a_function=<function args_and_kwargs at 0xffff01ab2c34>,
        inputs=({0, 1, 2, 'n'}, {'key': 'value'})
    ) ...TypeError: args_and_kwargs()
                    got an unexpected keyword argument 'first_input'.
                    Did you mean 'last_input'?
    
  • I open __init__.py from the functions folder in the src folder

  • I change argument to first_input in the definition and the return of the args_and_kwargs function, in src/functions/__init__.py

    functions/src/functions/__init__.py
     7def optional_arguments(
     8        first_input, last_input='doe',
     9    ):
    10    return first_input, last_input
    11
    12
    13def args_and_kwargs(first_input, last_input):
    14    return first_input, last_input
    15
    16
    17def keyword_arguments(first_input, last_input):
    

    the test passes.

  • I remove the other assertions from test_keyword_arguments in tests/test_functions.py

    functions/tests/test_functions.py
    90                    self.assertEqual(
    91                        a_function(
    92                            last_input=first,
    93                            first_input=second,
    94                        ),
    95                        (second, first)
    96                    )
    97
    98    def test_args_and_kwargs(self):
    
  • I add a git commit message

    terminal
    git commit -am \
    'test_keyword_arguments with for loops'
    

test_args_and_kwargs with for loops

test_positional_arguments and test_keyword_arguments now look the same, one uses for loops

self.assertEqual(
    function(
        last_input=something,
        first_input=something_else),
    (something_else, something)
)

RED: make it fail


I add the for loops for each one of the arguments and the positional_arguments, keyword_arguments, args_and_kwargs and optional_arguments functions

functions/tests/test_functions.py
 98    def test_args_and_kwargs(self):
 99        for first, second in (
100            (self.first, self.last),
101            (self.last, self.first),
102            (0, 1),
103            (self.a_tuple, self.a_list),
104            (self.a_set, self.a_dictionary),
105        ):
106            for a_function in (
107                src.functions.positional_arguments,
108                src.functions.keyword_arguments,
109                src.functions.args_and_kwargs,
110                src.functions.optional_arguments,
111            ):
functions/tests/test_functions.py
112                with self.subTest(
113                    a_function=a_function, inputs=(first, second)
114                ):
115                    self.assertEqual(
116                        a_function(first, second),
117                        (second, first)
118                    )
119                    self.assertEqual(
120                        a_function(
121                            last_input=first,
122                            first_input=second,
123                        ),
124                        (first, second)
125                    )
functions/tests/test_functions.py
126                    self.assertEqual(
127                        a_function(
128                            first, last_input=second,
129                        ),
130                        (second, first)
131                    )
132                    self.assertEqual(
133                        a_function(
134                            second, last_input=first,
135                        ),
136                        (first, second)
137                    )
138
139        self.assertEqual(
140            src.functions.args_and_kwargs(
141                self.first, last_input=self.last
142            ),
143            (self.first, self.last)
144        )

the terminal is my friend, and shows AssertionError for twenty sub tests.


GREEN: make it pass


  • I change the expectation of the assertion for positional arguments

    functions/tests/test_functions.py
    112                with self.subTest(
    113                    a_function=a_function, inputs=(first, second)
    114                ):
    115                    self.assertEqual(
    116                        a_function(first, second),
    117                        (first, second)
    118                    )
    119                    self.assertEqual(
    120                        a_function(
    121                            last_input=first,
    122                            first_input=second,
    123                        ),
    124                        (first, second)
    125                    )
    

    the terminal shows AssertionError for twenty sub tests for the assertion for keyword arguments.

  • I change the expectation of the assertion for keyword arguments

    functions/tests/test_functions.py
    119                    self.assertEqual(
    120                        a_function(
    121                            last_input=first,
    122                            first_input=second,
    123                        ),
    124                        (second, first)
    125                    )
    126                    self.assertEqual(
    127                        a_function(
    128                            first, last_input=second,
    129                        ),
    130                        (second, first)
    131                    )
    

    the terminal shows AssertionError for twenty sub tests for the first assertion for positional and keyword arguments.

  • I change the expectation of the first assertion for positional and keyword arguments

    functions/tests/test_functions.py
    126                    self.assertEqual(
    127                        a_function(
    128                            first, last_input=second,
    129                        ),
    130                        (first, second)
    131                    )
    132                    self.assertEqual(
    133                        a_function(
    134                            second, last_input=first,
    135                        ),
    136                        (first, second)
    137                    )
    

    the terminal shows AssertionError for twenty sub tests for the second assertion for positional and keyword arguments.

  • I change the expectation of the second assertion for positional and keyword arguments

    functions/tests/test_functions.py
    132                    self.assertEqual(
    133                        a_function(
    134                            second, last_input=first,
    135                        ),
    136                        (second, first)
    137                    )
    138
    139        self.assertEqual(
    140            src.functions.args_and_kwargs(
    141                self.first, last_input=self.last
    142            ),
    143            (self.first, self.last)
    144        )
    

    the test passes.


REFACTOR: make it better


  • I remove the other assertion from test_args_and_kwargs

    functions/tests/test_functions.py
    132                    self.assertEqual(
    133                        a_function(
    134                            second, last_input=first,
    135                        ),
    136                        (second, first)
    137                    )
    138
    139    def test_optional_arguments(self):
    
  • I remove test_positional_arguments and test_keyword_arguments because they are now covered by test_args_and_kwargs

    functions/tests/test_functions.py
    41    def test_why_use_a_for_loop(self):
    42        def add_x(number):
    43            return 3 + number
    44
    45        for a_number in range(1000):
    46            with self.subTest(a_number):
    47                self.assertEqual(
    48                    add_x(a_number), a_number+3
    49                )
    50
    51    def test_args_and_kwargs(self):
    
  • I add a git commit message

    terminal
    git commit -am \
    'test_args_and_kwargs with for loops'
    

close the project

  • I close tests/test_functions.py and src/functions/__init__.py

  • I click in the terminal where the tests are running

  • I use q on the keyboard to leave the tests

  • I change directory to the parent of functions

    terminal
    cd ..
    

review

  • I used for loops to remove repetition from the tests. If you did not go through this project and someone gave you this code, do you think you can tell what it is testing?


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 the microwave project with loops?


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.