test car with list comprehensions

I want to use for loops in the Car project. It has tests for a Car ignition with these inputs:

  • was the start button pressed?

  • is the key close to the ignition?

  • is the brake being pressed?

  • is the car in park?

the inputs gave me this truth table

key

brake

start

gear

output

close

pressed

pressed

in park

True

close

pressed

pressed

NOT in park

False

close

NOT pressed

pressed

in park

False

close

NOT pressed

pressed

NOT in park

False

key

brake

start

gear

output

NOT close

pressed

pressed

in park

False

NOT close

pressed

pressed

NOT in park

False

NOT close

NOT pressed

pressed

in park

False

NOT close

NOT pressed

pressed

NOT in park

False

key

brake

start

gear

output

close

pressed

NOT pressed

in park

False

close

pressed

NOT pressed

NOT in park

False

close

NOT pressed

NOT pressed

in park

False

close

NOT pressed

NOT pressed

NOT in park

False

key

brake

start

gear

output

NOT close

pressed

NOT pressed

in park

False

NOT close

pressed

NOT pressed

NOT in park

False

NOT close

NOT pressed

NOT pressed

in park

False

NOT close

NOT pressed

NOT pressed

NOT in park

False

the only time the Car starts is if the start button is pressed AND the key is close to the ignition AND the brake is being pressed AND the car gear is in park.


preview

This is the test I have at the end of the chapter

car/tests/test_car_w_loops.py
 1import src.car
 2import unittest
 3
 4
 5class TestCar(unittest.TestCase):
 6
 7    def test_car_ignition(self):
 8        booleans = (False, True)
 9        for start_is_pressed in booleans:
10            for key_is_close in booleans:
11              for brake_is_pressed in booleans:
12                  for in_park in booleans:
13                      with self.subTest(
14                          start_is_pressed=start_is_pressed,
15                          key_is_close=key_is_close,
16                          brake_is_pressed=brake_is_pressed,
17                          in_park=in_park,
18                      ):
19                          result = src.car.ignition(
20                              start_is_pressed=start_is_pressed,
21                              key_is_close=key_is_close,
22                              brake_is_pressed=brake_is_pressed,
23                              in_park=in_park,
24                          )
25                          try:
26                              self.assertFalse(result)
27                          except AssertionError:
28                              self.assertTrue(result)
29
30
31# Exceptions seen
32# AssertionError
33# NameError
34# AttributeError
35# TypeError
36# SyntaxError

open the project


extract test_car_ignition

RED: make it fail


  • I add a test with a for loop for all the cases

    car/tests/test_car.py
     5class TestCar(unittest.TestCase):
     6
     7    def test_car_ignition(self):
     8        booleans = (False, True)
     9        for start_is_pressed in booleans:
    10            for key_is_close in booleans:
    11              for brake_is_pressed in booleans:
    12                  for in_park in booleans:
    13                      with self.subTest(
    14                          start_is_pressed=start_is_pressed,
    15                          key_is_close=key_is_close,
    16                          brake_is_pressed=brake_is_pressed,
    17                          in_park=in_park,
    18                      ):
    
    car/tests/test_car.py
    19                          result = src.car.ignition(
    20                              start_is_pressed=start_is_pressed,
    21                              key_is_close=key_is_close,
    22                              brake_is_pressed=brake_is_pressed,
    23                              in_park=in_park,
    24                          )
    25                          self.assertEqual(result, 'BOOM!!!')
    26
    27    def test_park_w_brake_pressed_key_close_start_pressed(self):
    

    the terminal is my friend, and shows AssertionError

    terminal
    SUBFAILED(
        start_is_pressed=False, key_is_close=False,
        brake_is_pressed=False, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=False, key_is_close=False,
        brake_is_pressed=False, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=False, key_is_close=False,
        brake_is_pressed=True, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=False, key_is_close=False,
        brake_is_pressed=True, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    
    terminal
    SUBFAILED(
        start_is_pressed=False, key_is_close=True,
        brake_is_pressed=False, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=False, key_is_close=True,
        brake_is_pressed=False, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=False, key_is_close=True,
        brake_is_pressed=True, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=False, key_is_close=True,
        brake_is_pressed=True, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    
    terminal
    SUBFAILED(
        start_is_pressed=True, key_is_close=False,
        brake_is_pressed=False, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=True, key_is_close=False,
        brake_is_pressed=False, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=True, key_is_close=False,
        brake_is_pressed=True, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=True, key_is_close=False,
        brake_is_pressed=True, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    
    terminal
    SUBFAILED(
        start_is_pressed=True, key_is_close=True,
        brake_is_pressed=False, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=True, key_is_close=True,
        brake_is_pressed=False, in_park=True
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=True, key_is_close=True,
        brake_is_pressed=True, in_park=False
    ) ... AssertionError: False != 'BOOM!!!'
    SUBFAILED(
        start_is_pressed=True, key_is_close=True,
        brake_is_pressed=True, in_park=True
    ) ... AssertionError: True != 'BOOM!!!'
    

GREEN: make it pass


  • I change self.assertEqual(result, 'BOOM!!!') to handle the fifteen cases where the ignition function returns False

    car/tests/test_car.py
    19                          result = src.car.ignition(
    20                              start_is_pressed=start_is_pressed,
    21                              key_is_close=key_is_close,
    22                              brake_is_pressed=brake_is_pressed,
    23                              in_park=in_park,
    24                          )
    25                          self.assertFalse(result)
    26
    27    def test_park_w_brake_pressed_key_close_start_pressed(self):
    

    the terminal is my friend, and shows AssertionError for the one case where the Car starts.

    terminal
    SUBFAILED(
        start_is_pressed=True, key_is_close=True,
        brake_is_pressed=True, in_park=True
    ) ... AssertionError: True is not false
    
  • I move the assertion into a try statement for it

    car/tests/test_car.py
    19                          result = src.car.ignition(
    20                              start_is_pressed=start_is_pressed,
    21                              key_is_close=key_is_close,
    22                              brake_is_pressed=brake_is_pressed,
    23                              in_park=in_park,
    24                          )
    25                          try:
    26                              self.assertFalse(result)
    27                          except AssertionError:
    28                              self.assertTrue(result)
    29
    30    def test_park_w_brake_pressed_key_close_start_pressed(self):
    

    the test passes.


REFACTOR: make it better


  • I remove all the other tests because they are now covered by test_car_ignition

    car/tests/test_car.py
    25                          try:
    26                              self.assertFalse(result)
    27                          except AssertionError:
    28                              self.assertTrue(result)
    29
    30
    31# Exceptions seen
    
  • I add a git commit message in the other terminal

    terminal
    git commit -am \
    'extract test_car_ignition'
    

close the project

  • I close tests/test_car.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 Car

    terminal
    cd ..
    

review

Once again, I used four nested for loops (ugly) to put all the tests together which leaves me with less lines of code and something that is harder to understand.

There has to be a better way that does not write this many loops.


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 an Elevator?


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.