test elevator with list comprehensions
I want to use for loops in the Elevator project. It has tests for an Elevator Controller that will MOVE the Elevator Car to a floor when I push a button for the floor based on these inputs:
was the number for a floor pushed?
are the doors closed?
is it above the weight limit?
was the emergency button pushed?
the inputs gave me this truth table
floor button |
doors |
weight limit |
emergency button |
output |
|---|---|---|---|---|
pushed |
closed |
above |
pushed |
False |
pushed |
closed |
above |
NOT pushed |
False |
pushed |
closed |
below |
pushed |
False |
pushed |
closed |
below |
NOT pushed |
True |
floor button |
doors |
weight limit |
emergency button |
output |
|---|---|---|---|---|
pushed |
open |
above |
pushed |
False |
pushed |
open |
above |
NOT pushed |
False |
pushed |
open |
below |
pushed |
False |
pushed |
open |
below |
NOT pushed |
False |
floor button |
doors |
weight limit |
emergency button |
output |
|---|---|---|---|---|
NOT pushed |
closed |
above |
pushed |
False |
NOT pushed |
closed |
above |
NOT pushed |
False |
NOT pushed |
closed |
below |
pushed |
False |
NOT pushed |
closed |
below |
NOT pushed |
False |
floor button |
doors |
weight limit |
emergency button |
output |
|---|---|---|---|---|
NOT pushed |
open |
above |
pushed |
False |
NOT pushed |
open |
above |
NOT pushed |
False |
NOT pushed |
open |
below |
pushed |
False |
NOT pushed |
open |
below |
NOT pushed |
False |
The only time this elevator moves up or down is when the button for a floor is pushed AND the doors are closed AND the Elevator is NOT above the weight limit, and the emergency button is NOT pushed.
preview
These is the test I have at the end of the chapter
1import src.elevator
2import unittest
3
4
5class TestElevator(unittest.TestCase):
6
7 def test_elevator_controller(self):
8 booleans = (False, True)
9 for number_pushed in booleans:
10 for doors_closed in booleans:
11 for above_weight in booleans:
12 for emergency in booleans:
13 with self.subTest(
14 number_pushed=number_pushed,
15 doors_closed=doors_closed,
16 above_weight=above_weight,
17 emergency=emergency,
18 ):
19 result = src.elevator.controller(
20 number_pushed=number_pushed,
21 doors_closed=doors_closed,
22 above_weight=above_weight,
23 emergency=emergency,
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
I open a terminal
I change directory to the elevator folder in the
pumping_pythonfolderI open
test_elevator.pyfrom thetestsfolderI use pytest-watcher to run the tests automatically
extract test_elevator_controller
RED: make it fail
I add a test with a for loop for all the cases
5class TestElevator(unittest.TestCase):
6
7 def test_elevator_controller(self):
8 booleans = (False, True)
9 for number_pushed in booleans:
10 for doors_closed in booleans:
11 for above_weight in booleans:
12 for emergency in booleans:
13 with self.subTest(
14 number_pushed=number_pushed,
15 doors_closed=doors_closed,
16 above_weight=above_weight,
17 emergency=emergency,
18 ):
5 result = src.elevator.controller(
6 number_pushed=number_pushed,
7 doors_closed=doors_closed,
8 above_weight=above_weight,
9 emergency=emergency,
10 )
11 self.assertEqual(result, 'BOOM!!!')
12
13 def test_above_weight_doors_closed_number_pushed(self):
the terminal is my friend, and shows AssertionError
SUBFAILED(
number_pushed=False, doors_closed=False,
above_weight=False, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=False,
above_weight=False, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=False,
above_weight=True, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=False,
above_weight=True, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=True,
above_weight=False, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=True,
above_weight=False, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=True,
above_weight=True, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=False, doors_closed=True,
above_weight=True, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=False,
above_weight=False, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=False,
above_weight=False, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=False,
above_weight=True, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=False,
above_weight=True, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=True,
above_weight=False, emergency=False
) ... AssertionError: True != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=True,
above_weight=False, emergency=True
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=True,
above_weight=True, emergency=False
) ... AssertionError: False != 'BOOM!!!'
SUBFAILED(
number_pushed=True, doors_closed=True,
above_weight=True, emergency=True
) ... AssertionError: False != 'BOOM!!!'
GREEN: make it pass
I change
self.assertEqual(result, 'BOOM!!!')to handle the fifteen cases where thecontrollerfunctions returns False19 result = src.elevator.controller( 20 number_pushed=number_pushed, 21 doors_closed=doors_closed, 22 above_weight=above_weight, 23 emergency=emergency, 24 ) 25 self.assertFalse(result) 26 27 def test_above_weight_doors_closed_number_pushed(self):the terminal is my friend, and shows AssertionError
I move the assertion into a try statement for it
19 result = src.elevator.controller( 20 number_pushed=number_pushed, 21 doors_closed=doors_closed, 22 above_weight=above_weight, 23 emergency=emergency, 24 ) 25 try: 26 self.assertFalse(result) 27 except AssertionError: 28 self.assertTrue(result) 29 30 def test_above_weight_doors_closed_number_pushed(self):the test passes.
REFACTOR: make it better
I remove all the other tests because they are now covered by test_elevator_controller
I add a git commit message
close the project
I close
tests/test_elevator.pyI 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 Elevator
review
I also used four nested for loops to make one test for all sixteen cases. There has to be a better way that looks better.
code from the chapter
what is next?
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.