functions 3

Since I know how to use for loops, I can do better with the assertions of test_why_use_a_function


open the project

  • I change directory to the functions folder

    cd functions
    

    the terminal shows I am in the functions folder

    .../pumping_python/functions
    
  • I use pytest-watcher to run the tests

    uv run pytest-watcher . --now
    

    the terminal shows

    rootdir: .../pumping_python/functions
    configfile: pyproject.toml
    collected 12 items
    
    tests/test_functions.py ............                          [100%]
    
    ======================= 12 passed in X.YZs =========================
    
  • I hold ctrl on the keyboard, then click on tests/test_functions.py to open it in the editor


a better way to test why use a function


RED: make it fail


  • I add a variable to test_why_use_a_function

     7    def test_why_use_a_function(self):
     8        def add(x=3, y=0):
     9            return x + y
    10
    11        x = 4
    12        numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    13
    14        y = 0
    15        self.assertEqual(add(x, y), x+y)
    
  • I add a for loop with an assertion and the subTest method

    11        x = 4
    12        numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    13        for y in numbers:
    14            with self.subTest(y=y):
    15                self.assertEqual(add(x, y), x+x)
    16
    17        y = 0
    18        self.assertEqual(add(x, y), x+y)
    

    the terminal shows AssertionError

    SUBFAILED(y=0) ... - AssertionError: 4 != 104
    SUBFAILED(y=1) ... - AssertionError: 5 != 104
    SUBFAILED(y=2) ... - AssertionError: 6 != 104
    SUBFAILED(y=3) ... - AssertionError: 7 != 104
    SUBFAILED(y=4) ... - AssertionError: 8 != 104
    SUBFAILED(y=5) ... - AssertionError: 9 != 104
    SUBFAILED(y=6) ... - AssertionError: 10 != 104
    SUBFAILED(y=7) ... - AssertionError: 11 != 104
    SUBFAILED(y=8) ... - AssertionError: 12 != 104
    SUBFAILED(y=9) ... - AssertionError: 13 != 104
    

GREEN: make it pass


I change the calculation to x+y

11          x = 4
12          numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
13          for y in numbers:
14              with self.subTest(y=y):
15                  self.assertEqual(add(x, y), x+y)

the test passes


REFACTOR: make it better


  • I remove the other assertions because the for loop does what they do

     7      def test_why_use_a_function(self):
     8          def add(x=3, y=0):
     9              return x + y
    10
    11          x = 4
    12          numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    13          for y in numbers:
    14              with self.subTest(y=y):
    15                  self.assertEqual(add(x, y), x+y)
    16
    17      def test_making_a_function_w_pass(self):
    
  • I add a for loop for the value of x

    11          x = 4
    12          numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    13          for y in numbers:
    14              for x in numbers:
    15                  with self.subTest(x=x, y=y):
    16                      self.assertEqual(add(x, y), x+100)
    

    the terminal shows AssertionError

    ================== 100 failed, 12 passed in X.YZs ===================
    

    the two for loops go through every combination of x and y

    (x, y)
    (0, 0)
    (0, 1)
    (0, 2)
    ...
    (5, 0)
    (5, 1)
    (5, 2)
    ...
    (9, 7)
    (9, 8)
    (9, 9)
    
  • I change the calculation in the expectation to the right thing

    16                    self.assertEqual(add(x, y), x+y)
    

    the test passes

  • I remove the x variable, then the default values from the add function

     7    def test_why_use_a_function(self):
     8        def add(x, y):
     9            return x + y
    10
    11        numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    12        for y in numbers:
    13            for x in numbers:
    14                with self.subTest(x=x, y=y):
    15                    self.assertEqual(add(x, y), x+y)
    

    the test is still green

  • I can use a list comprehension instead of the 2 for loops

    11        numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    12        for y in numbers:
    13            for x in numbers:
    14                with self.subTest(x=x, y=y):
    15                    self.assertEqual(add(x, y), x+y)
    16
    17        for x, y in ((x, y) for x in numbers for y in numbers):
    18            with self.subTest(x=x, y=y):
    19                self.assertEqual(add(x, y), x+100)
    

    the terminal shows AssertionError

    ================== 100 failed, 12 passed in X.YZs ===================
    
  • I change the calculation in the expectation

    15                self.assertEqual(add(x, y), x+y)
    

    the test passes. That used for 3 times, confusing.

  • I can do the same thing with the product method from the itertools module which comes with Python, it needs an import statement

    17        for x, y in ((x, y) for x in numbers for y in numbers):
    18            with self.subTest(x=x, y=y):
    19                self.assertEqual(add(x, y), x+y)
    20
    21        import itertools
    22        for x, y in itertools.product(numbers, repeat=2):
    23            with self.subTest(x=x, y=y):
    24                self.assertEqual(add(x, y), x+100)
    

    the terminal shows AssertionError

    ================== 100 failed, 12 passed in X.YZs ===================
    
  • I change the expectation

    24                self.assertEqual(add(x, y), x+y)
    25
    26    def test_making_a_function_w_pass(self):
    

    the test passes, not as confusing.

  • I can use a range object to make the test use more than 10 numbers

    11        # numbers = range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    12        numbers = range(-10, 10)
    13        for y in numbers:
    

    the test is still green

  • I change the expectation in the first assertion

    11        # numbers = range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    12        numbers = range(-10, 10)
    13        for y in numbers:
    14            for x in numbers:
    15                with self.subTest(x=x, y=y):
    16                    self.assertEqual(add(x, y), x+100)
    

    the terminal shows AssertionError

    ================== 400 failed, 12 passed in X.YZs ===================
    

    the test takes longer to run because there are more numbers to calculate

  • I change the expectation back then remove the commented line

     5class TestFunctions(unittest.TestCase):
     6
     7    def test_why_use_a_function(self):
     8        def add(x, y):
     9            return x + y
    10
    11        numbers = range(-10, 10)
    12        for y in numbers:
    13            for x in numbers:
    14                with self.subTest(x=x, y=y):
    15                    self.assertEqual(add(x, y), x+y)
    16
    17        for x, y in ((x, y) for x in numbers for y in numbers):
    18            with self.subTest(x=x, y=y):
    19                self.assertEqual(add(x, y), x+y)
    20
    21        import itertools
    22        for x, y in itertools.product(numbers, repeat=2):
    23            with self.subTest(x=x, y=y):
    24                self.assertEqual(add(x, y), x+y)
    25
    26    def test_making_a_function_w_pass(self):
    

    the test is green again

I can use a for loop to remove duplication


close the project

  • I close test_functions.py and functions.py in the editor

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

  • I change directory to the parent of functions

    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory


review

I used a for loop to remove repetition.

Why did my “list comprehensions” look like tuples and not lists?


code from the chapter

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


what is next?

you know

Would you like to test dictionaries?


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