how to make a calculator part 6
I can use a dictionary to test the calculator functions as long as its values are numbers
open the project
I change directory to the
calculatorfoldercd calculatorthe terminal shows I am in the
calculatorfolder.../pumping_python/calculatorI activate the virtual environment
source .venv/bin/activateAttention
on Windows without Windows Subsystem for Linux use
.venv/bin/activate.ps1NOTsource .venv/bin/activate.venv/scripts/activate.ps1the terminal shows
(.venv) .../pumping_python/calculatorI use
pytest-watchto run the tests
pytest-watch
the terminal shows
rootdir: .../pumping_python/calculator
collected 7 items
tests/test_calculator.py ....... [100%]
============================ 7 passed in X.YZs =============================
I hold ctrl on the keyboard and click on
tests/test_calculator.pyto open it in the editor
test_calculator_w_dictionary_items
RED: make it fail
I add a new test to use a dictionary to test the calculator
119 self.assertEqual(
120 src.calculator.subtract(*a_list),
121 self.random_first_number-self.random_second_number
122 )
123
124 def test_calculator_w_dictionary_items(self):
125 two_numbers = {
126 'x': self.random_first_number,
127 'y': self.random_second_number,
128 }
129
130 self.assertEqual(
131 src.calculator.add(two_numbers['x'], two_numbers['y']),
132 self.random_first_number+self.random_first_number
133 )
134
135 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
136 not_two_numbers = [0, 1, 2]
the terminal shows AssertionError
AssertionError: ABC.DEFGHIJKLMNOPQ != RST.UVWXYZABCDEFG
GREEN: make it pass
I change the expectation to the right calculation
130 self.assertEqual(
131 src.calculator.add(two_numbers['x'], two_numbers['y']),
132 self.random_first_number+self.random_second_number
133 )
the test passes
REFACTOR: make it better
I add an assertion for the divide function
130 self.assertEqual( 131 src.calculator.add(two_numbers['x'], two_numbers['y']), 132 self.random_first_number+self.random_second_number 133 ) 134 self.assertEqual( 135 src.calculator.divide(two_numbers['x'], two_numbers['y']), 136 self.random_first_number*self.random_second_number 137 )the terminal shows AssertionError
AssertionError: D.EFGHIJKLMNOPQRST != UVWXY.ZABCDEFGHIJI change the calculation
134 self.assertEqual( 135 src.calculator.divide(two_numbers['x'], two_numbers['y']), 136 self.random_first_number/self.random_second_number 137 )the test passes
I add another assertion
134 self.assertEqual( 135 src.calculator.divide(two_numbers['x'], two_numbers['y']), 136 self.random_first_number/self.random_second_number 137 ) 138 self.assertEqual( 139 src.calculator.multiply(two_numbers['y'], two_numbers['y']), 140 self.random_first_number*self.random_second_number 141 )the terminal shows AssertionError
AssertionError: EFGHIJ.KLMNOPQRSTU != VWXYZ.ABCDEFGHIJKLI change the expectation
123 self.assertEqual( 124 src.calculator.multiply(two_numbers['y'], two_numbers['y']), 125 self.random_second_number*self.random_second_number 126 )the test passes
I add an assertion for the subtract function
138 self.assertEqual( 139 src.calculator.multiply(two_numbers['y'], two_numbers['y']), 140 self.random_second_number*self.random_second_number 141 ) 142 self.assertEqual( 143 src.calculator.subtract(two_numbers['x'], two_numbers['x']), 144 self.random_first_number-self.random_second_number 145 )the terminal shows AssertionError
AssertionError: 0.0 != FGH.IJKLMNOPQRSTUI change the expectation to match
142 self.assertEqual( 143 src.calculator.subtract(two_numbers['x'], two_numbers['x']), 144 self.random_first_number-self.random_first_number 145 )the test passes
Python allows me use a double starred expression like I did in test_functions_w_unknown_arguments. I add an assertion with it
142 self.assertEqual( 143 src.calculator.subtract(two_numbers['x'], two_numbers['x']), 144 self.random_first_number-self.random_first_number 145 ) 146 self.assertEqual( 147 src.calculator.add(**two_numbers), 148 self.random_first_number-self.random_second_number 149 )TypeError: only_takes_numbers.<locals>.wrapper() got an unexpected keyword argument 'x'the names of the keys in the
two_numbersdictionary must be the same as the names of the arguments the calculator functions receive -first_inputandsecond_inputnotxandy. I changexandytofirst_inputandsecond_inputin the test124 def test_calculator_w_dictionary_items(self): 125 two_numbers = { 126 'first_input': self.random_first_number, 127 'second_input': self.random_second_number, 128 } 129 130 self.assertEqual( 131 src.calculator.add(two_numbers['first_input'], two_numbers['second_input']), 132 self.random_first_number+self.random_second_number 133 ) 134 self.assertEqual( 135 src.calculator.divide(two_numbers['first_input'], two_numbers['second_input']), 136 self.random_first_number/self.random_second_number 137 ) 138 self.assertEqual( 139 src.calculator.multiply(two_numbers['second_input'], two_numbers['second_input']), 140 self.random_second_number*self.random_second_number 141 ) 142 self.assertEqual( 143 src.calculator.subtract(two_numbers['first_input'], two_numbers['first_input']), 144 self.random_first_number-self.random_first_number 145 )the terminal shows AssertionError
AssertionError: VWX.YZABCDEFGHIJK != LMN.OPQRSTUVWXYZABCI change the calculation in the assertion
146 self.assertEqual( 147 src.calculator.add(**two_numbers), 148 self.random_first_number+self.random_second_number 149 )the test passes
I add another assertion
146 self.assertEqual( 147 src.calculator.add(**two_numbers), 148 self.random_first_number+self.random_second_number 149 ) 150 self.assertEqual( 151 src.calculator.divide(**two_numbers), 152 self.random_first_number*self.random_second_number 153 )the terminal shows AssertionError
AssertionError: H.IJKLMNOPQRSTUVWX != YZABCD.EFGHIJKLMNOI change the calculation
150 self.assertEqual( 151 src.calculator.divide(**two_numbers), 152 self.random_first_number/self.random_second_number 153 )the test passes
I add an assertion for the multiply function
150 self.assertEqual( 151 src.calculator.divide(**two_numbers), 152 self.random_first_number/self.random_second_number 153 ) 154 self.assertEqual( 155 src.calculator.multiply(**two_numbers), 156 self.random_first_number/self.random_second_number 157 )the terminal shows AssertionError
AssertionError: IJKLMN.OPQRSTUVWX != Y.ZABCDEFGHIJKLMNOPI change the calculation
154 self.assertEqual( 155 src.calculator.multiply(**two_numbers), 156 self.random_first_number*self.random_second_number 157 )the test passes
I add the next assertion
154 self.assertEqual( 155 src.calculator.multiply(**two_numbers), 156 self.random_first_number*self.random_second_number 157 ) 158 self.assertEqual( 159 src.calculator.subtract(**two_numbers), 160 self.random_first_number+self.random_second_number 161 )the terminal shows AssertionError
AssertionError: JKL.MNOPQRSTUVWXYZ != ABC.DEFGHIJKLMNOPI change the expectation
158 self.assertEqual( 159 src.calculator.subtract(**two_numbers), 160 self.random_first_number-self.random_second_number 161 )the test passes
I can use the values method to make a list to test the calculator in
test_calculator_w_list_items88 def test_calculator_w_list_items(self): 89 # two_numbers = [self.random_first_number, self.random_second_number] 90 a_dictionary = { 91 'x': self.random_first_number, 92 'y': self.random_second_number 93 } 94 two_numbers = list(a_dictionary.values()) 95 96 self.assertEqual( 97 src.calculator.add(two_numbers[0], two_numbers[1]), 98 self.random_first_number+self.random_second_number 99 )the test is still green
I can also use a dictionary with a for loop to make
test_calculator_sends_message_when_input_is_not_a_numbermore complex and simpler58def test_calculator_sends_message_when_input_is_not_a_number(self): 59 error_message = 'Excuse me?! Numbers only. Try again...' 60 61 arithmetic = { 62 'add': src.calculator.add, 63 'subtract': src.calculator.subtract, 64 'multiply': src.calculator.multiply, 65 'divide': src.calculator.divide 66 } 67 68 for data in ( 69 None, 70 True, False, 71 str(), 'text', 72 tuple(), (0, 1, 2, 'n'), 73 list(), [0, 1, 2, 'n'], 74 set(), {0, 1, 2, 'n'}, 75 dict(), {'key': 'value'}, 76 ): 77 with self.subTest(i=data): 78 for operation in arithmetic: 79 self.assertEqual( 80 arithmetic[operation](data, a_random_number), 81 'BOOM' 82 ) 83 self.assertEqual( 84 src.calculator.add(data, a_random_number()), 85 error_message 86 )the terminal shows AssertionError for every case in the iterable
SUBFAILED(i=None) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=True) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=False) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i='') tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i='text') tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=()) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=(0, 1, 2, 'n')) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=[]) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=[0, 1, 2, 'n']) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i=set()) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i={0, 1, 2, 'n'}) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i={}) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM' SUBFAILED(i={'key': 'value'}) tests/test_calculator.py::TestCalculator::test_calculator_sends_message_when_input_is_not_a_number - AssertionError: 'Excuse me?! Numbers only. Try again...' != 'BOOM'the test works
I change the expectation
77 with self.subTest(i=data): 78 for operation in arithmetic: 79 self.assertEqual( 80 arithmetic[operation](data, a_random_number), 81 error_message 82 )the test passes
I remove the other assertions
58 def test_calculator_sends_message_when_input_is_not_a_number(self): 59 error_message = 'Excuse me?! Numbers only. Try again...' 60 61 arithmetic = { 62 'add': src.calculator.add, 63 'subtract': src.calculator.subtract, 64 'multiply': src.calculator.multiply, 65 'divide': src.calculator.divide 66 } 67 68 for data in ( 69 None, 70 True, False, 71 str(), 'text', 72 tuple(), (0, 1, 2, 'n'), 73 list(), [0, 1, 2, 'n'], 74 set(), {0, 1, 2, 'n'}, 75 dict(), {'key': 'value'}, 76 ): 77 with self.subTest(i=data): 78 for operation in arithmetic: 79 self.assertEqual( 80 arithmetic[operation](data, a_random_number), 81 error_message 82 ) 83 84 def test_calculator_w_list_items(self):this solution is not as easy to read as what was there before especially for someone new to Python
test_calculator_functions
I want to use a dictionary to write one test that covers all the 4 calculator functions
RED: make it pass
I add a new test
173 with self.assertRaises(TypeError): 174 src.calculator.subtract(*not_two_numbers) 175 176 def test_calculator_functions(self): 177 arithmetic = { 178 'addition': src.calculator.add, 179 'subtraction': src.calculator.subtract, 180 'division': src.calculator.divide, 181 'multiplication': src.calculator.multiply 182 } 183 184 for operation in arithmetic: 185 with self.subTest(operation=operation): 186 self.assertEqual( 187 arithmetic[operation](self.random_first_number, self.random_second_number), 188 'BOOM!!!' 189 ) 190 191 192# Exceptions seenthe terminal shows AssertionError for the 4 arithmetic operations
SUBFAILED(operation='addition') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: QRS.TUVWXYZABCDEF != 'BOOM!!!' SUBFAILED(operation='subtraction') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: GHI.JKLMNOPQRSTUVWX != 'BOOM!!!' SUBFAILED(operation='division') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: Y.ABCDEFGHIJKLMNOP != 'BOOM!!!' SUBFAILED(operation='multiplication') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: QRSTUV.WXYZABCDEFG != 'BOOM!!!'
GREEN: make it pass
I need a way to add the calculations for each operation to the assertion. I add another dictionary
181 'multiplication': src.calculator.multiply 182 } 183 data = { 184 'addition': self.random_first_number+self.random_second_number, 185 'subtraction': self.random_first_number-self.random_second_number, 186 'division': self.random_first_number/self.random_second_number, 187 'multiplication': self.random_first_number*self.random_second_number, 188 } 189 190 for operation in arithmetic:I use the new dictionary in the calculation in the assertion
190 for operation in arithmetic: 191 with self.subTest(operation=operation): 192 self.assertEqual( 193 arithmetic[operation](self.random_first_number, self.random_second_number), 194 data[operation] 195 )the test passes
REFACTOR: make it better
the two dictionaries in this test have the same keys. I put the dictionaries together
187 'multiplication': self.random_first_number*self.random_second_number, 188 } 189 190 arithmetic_tests = { 191 'addition': { 192 'function': src.calculator.add, 193 'expectation': self.random_first_number+self.random_second_number, 194 }, 195 'subtraction': { 196 'function': src.calculator.subtract, 197 'expectation': self.random_first_number-self.random_second_number, 198 }, 199 'division': { 200 'function': src.calculator.divide, 201 'expectation': self.random_first_number/self.random_second_number, 202 }, 203 'multiplication': { 204 'function': src.calculator.multiply, 205 'expectation': self.random_first_number*self.random_second_number, 206 } 207 } 208 209 for operation in arithmetic:I add a new assertion in a for loop with the subTest method
213 data[operation] 214 ) 215 216 for operation in arithmetic_tests: 217 with self.subTest(operation=operation): 218 self.assertEqual( 219 arithmetic_tests[operation]['function']( 220 self.random_first_number, 221 self.random_second_number 222 ), 223 'BOOM!!!' 224 ) 225 226 227def test_addition(self):the terminal shows AssertionError:
SUBFAILED(operation='addition') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: HIJ.KLMNOPQRSTUVW != 'BOOM!!!' SUBFAILED(operation='subtraction') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: XYZA.BCDEFGHIJKLMN != 'BOOM!!!' SUBFAILED(operation='division') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: NOP.QRSTUVWXYZABCDEF != 'BOOM!!!' SUBFAILED(operation='multiplication') tests/test_calculator.py::TestCalculator::test_calculator_functions - AssertionError: GHIJKLM.NOPQRSTUVWX != 'BOOM!!!'I change the expectation
216 for operation in arithmetic_tests: 217 with self.subTest(operation=operation): 218 self.assertEqual( 219 arithmetic_tests[operation]['function']( 220 self.random_first_number, 221 self.random_second_number 222 ), 223 arithmetic_tests[operation]['expectation'] 224 )the test passes
I remove the other dictionaries and for loop
176 def test_calculator_functions(self): 177 arithmetic_tests = { 178 'addition': { 179 'function': src.calculator.add, 180 'expectation': self.random_first_number+self.random_second_number, 181 }, 182 'subtraction': { 183 'function': src.calculator.subtract, 184 'expectation': self.random_first_number-self.random_second_number, 185 }, 186 'division': { 187 'function': src.calculator.divide, 188 'expectation': self.random_first_number/self.random_second_number, 189 }, 190 'multiplication': { 191 'function': src.calculator.multiply, 192 'expectation': self.random_first_number*self.random_second_number, 193 } 194 } 195 196 for operation in arithmetic_tests: 197 with self.subTest(operation=operation): 198 self.assertEqual( 199 arithmetic_tests[operation]['function']( 200 self.random_first_number, 201 self.random_second_number 202 ), 203 arithmetic_tests[operation]['expectation'] 204 )I remove the
test_addition,test_subtraction,test_multiplicationclass TestCalculator(unittest.TestCase): def setUp(self): self.random_first_number = a_random_number() self.random_second_number = a_random_number() def test_division(self):I need a way to handle ZeroDivisionError in
test_calculator_functionsfor the divide function. I changerandom_second_numberto0in the setUp method to make ZeroDivisionError happen in the tests12 def setUp(self): 13 self.random_first_number = a_random_number() 14 # self.random_second_number = a_random_number() 15 self.random_second_number = 0 16 17 def test_division(self):the terminal shows ZeroDivisionError for 3 tests
FAILED tests/test_calculator.py::TestCalculator::test_calculator_functions - ZeroDivisionError: float division by zero FAILED tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - ZeroDivisionError: float division by zero FAILED tests/test_calculator.py::TestCalculator::test_calculator_w_list_items - ZeroDivisionError: float division by zeroI use an exception handler to add a new class attribute (variable) for the result of division
15 self.random_second_number = 0 16 try: 17 self.division_result = self.random_first_number / self.random_second_number 18 except ZeroDivisionError: 19 self.division_result = 'undefined: I cannot divide by 0'I use the new class attribute (variable) in
test_calculator_functions46 'division': { 47 'function': src.calculator.divide, 48 # 'expectation': self.random_first_number/self.random_second_number, 49 'expectation': self.division_result, 50 },the terminal shows ZeroDivisionError for 2 tests
FAILED tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - ZeroDivisionError: float division by zero FAILED tests/test_calculator.py::TestCalculator::test_calculator_w_list_items - ZeroDivisionError: float division by zeroprogress
I add the class attribute (variable) to
test_calculator_w_list_items105 self.assertEqual( 106 src.calculator.divide(two_numbers[-2], two_numbers[-1]), 107 # self.random_first_number/self.random_second_number 108 self.division_result 109 )and
122 self.assertEqual( 123 src.calculator.divide(*two_numbers), 124 # self.random_first_number/self.random_second_number 125 self.division_result 126 )the terminal shows ZeroDivisionError for 1 test
FAILED tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - ZeroDivisionError: float division by zeroI add the class attribute (variable) to
test_calculator_w_dictionary_items146 self.assertEqual( 147 src.calculator.divide(two_numbers['first_input'], two_numbers['second_input']), 148 # self.random_first_number/self.random_second_number 149 self.division_result 150 )and
163 self.assertEqual( 164 src.calculator.divide(**two_numbers), 165 # self.random_first_number/self.random_second_number 166 self.division_result 167 )the terminal shows green. Lovely!
I remove the commented lines I added
I remove
test_divisiondef setUp(self): self.random_first_number = a_random_number() # self.random_second_number = a_random_number() self.random_second_number = 0 try: self.division_result = self.random_first_number / self.random_second_number except ZeroDivisionError: self.division_result = 'undefined: I cannot divide by 0' def test_calculator_functions(self):I change
self.random_second_numberback to a random float12def setUp(self): 13 self.random_first_number = a_random_number() 14 self.random_second_number = a_random_number() 15 try: 16 self.division_result = self.random_first_number / self.random_second_number 17 except ZeroDivisionError: 18 self.division_result = 'undefined: I cannot divide by 0'all tests are passing
the dictionaries in
test_calculator_functionsandtest_calculator_sends_message_when_input_is_not_a_numberare similar, I add a new dictionary in the setUp method17 except ZeroDivisionError: 18 self.division_result = 'undefined: I cannot divide by 0' 19 20 self.arithmetic_tests = { 21 'addition': { 22 'function': src.calculator.add, 23 'expectation': self.random_first_number+self.random_second_number, 24 }, 25 'subtraction': { 26 'function': src.calculator.subtract, 27 'expectation': self.random_first_number-self.random_second_number, 28 }, 29 'division': { 30 'function': src.calculator.divide, 31 'expectation': self.division_result, 32 }, 33 'multiplication': { 34 'function': src.calculator.multiply, 35 'expectation': self.random_first_number*self.random_second_number, 36 } 37 } 38 39 def test_calculator_functions(self):I use it in
test_calculator_functions59 for operation in self.arithmetic_tests: 60 with self.subTest(operation=operation): 61 self.assertEqual( 62 self.arithmetic_tests[operation]['function']( 63 self.random_first_number, 64 self.random_second_number 65 ), 66 self.arithmetic_tests[operation]['expectation'] 67 )the test is green
I remove the
arithemtic_testsdictionary fromtest_calculator_functions39 def test_calculator_functions(self): 40 for operation in self.arithmetic_tests: 41 with self.subTest(operation=operation): 42 self.assertEqual( 43 self.arithmetic_tests[operation]['function']( 44 self.random_first_number, 45 self.random_second_number 46 ), 47 self.arithmetic_tests[operation]['expectation'] 48 ) 49 50 def test_calculator_sends_message_when_input_is_not_a_number(self):still green
I use the new class attribute (variable) in
test_calculator_sends_message_when_input_is_not_a_number69 with self.subTest(i=data): 70 # for operation in arithmetic: 71 for operation in self.arithmetic_tests: 72 self.assertEqual( 73 # arithmetic[operation](data, a_random_number), 74 self.arithmetic_tests[operation]['function'](data, a_random_number), 75 error_message 76 )the test is still green
I remove the commented lines and the
arithmeticdictionary50 def test_calculator_sends_message_when_input_is_not_a_number(self): 51 error_message = 'Excuse me?! Numbers only. Try again...' 52 53 for data in ( 54 None, 55 True, False, 56 str(), 'text', 57 tuple(), (0, 1, 2, 'n'), 58 list(), [0, 1, 2, 'n'], 59 set(), {0, 1, 2, 'n'}, 60 dict(), {'key': 'value'}, 61 ): 62 with self.subTest(i=data): 63 for operation in self.arithmetic_tests: 64 self.assertEqual( 65 self.arithmetic_tests[operation]['function'](data, a_random_number), 66 error_message 67 ) 68 69 def test_calculator_w_list_items(self):still green
I add a for loop to use the
arithmetic_testsdictionary in test_calculator_raises_type_error_when_given_more_than_two_inputs158 with self.assertRaises(TypeError): 159 src.calculator.subtract(*not_two_numbers) 160 161 for operation in self.arithmetic_tests: 162 with self.subTest(operation=operation): 163 self.arithmetic_tests[operation]['function'](*not_two_numbers) 164 165 166# Exceptions seenthe terminal shows TypeError for all 4 cases
SUBFAILED(operation='addition') tests/test_calculator.py::TestCalculator::test_calculator_raises_type_error_when_given_more_than_two_inputs - TypeError: only_takes_numbers.<locals>.wrapper() takes 2 positional arguments but 3 were ... SUBFAILED(operation='subtraction') tests/test_calculator.py::TestCalculator::test_calculator_raises_type_error_when_given_more_than_two_inputs - TypeError: only_takes_numbers.<locals>.wrapper() takes 2 positional arguments but 3 were ... SUBFAILED(operation='division') tests/test_calculator.py::TestCalculator::test_calculator_raises_type_error_when_given_more_than_two_inputs - TypeError: only_takes_numbers.<locals>.wrapper() takes 2 positional arguments but 3 were ... SUBFAILED(operation='multiplication') tests/test_calculator.py::TestCalculator::test_calculator_raises_type_error_when_given_more_than_two_inputs - TypeError: only_takes_numbers.<locals>.wrapper() takes 2 positional arguments but 3 were ...I add the assertRaises method
161 for operation in self.arithmetic_tests: 162 with self.subTest(operation=operation): 163 with self.assertRaises(TypeError): 164 self.arithmetic_tests[operation]['function'](*not_two_numbers)the test passes
I remove the other assertions
149 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self): 150 not_two_numbers = [0, 1, 2] 151 152 for operation in self.arithmetic_tests: 153 with self.subTest(operation=operation): 154 with self.assertRaises(TypeError): 155 self.arithmetic_tests[operation]['function'](*not_two_numbers) 156 157 158# Exceptions seenstill green
I no longer need the variable, I remove it and use the list directly in the assertion
149 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self): 150 for operation in self.arithmetic_tests: 151 with self.subTest(operation=operation): 152 with self.assertRaises(TypeError): 153 self.arithmetic_tests[operation]['function'](*[0, 1, 2])the test is still green
Python allows me to put the 2 with contexts together in one statement
149 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self): 150 for operation in self.arithmetic_tests: 151 # with self.subTest(operation=operation): 152 # with self.assertRaises(TypeError): 153 with ( 154 self.subTest(operation=operation), 155 self.assertRaises(TypeError), 156 ): 157 self.arithmetic_tests[operation]['function'](*[0, 1, 2])green
I remove the commented lines
137 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self): 138 for operation in self.arithmetic_tests: 139 with ( 140 self.subTest(operation=operation), 141 self.assertRaises(TypeError), 142 ): 143 self.arithmetic_tests[operation]['function'](*[0, 1, 2])I add a for loop to
test_calculator_w_list_items105 self.assertEqual( 106 src.calculator.subtract(*two_numbers), 107 self.random_first_number-self.random_second_number 108 ) 109 110 for operation in self.arithmetic_tests: 111 with self.subTest(operation=operation): 112 self.assertEqual( 113 self.arithmetic_tests[operation]['function']( 114 *two_numbers 115 ), 116 'BOOM!!!' 117 ) 118 119 def test_calculator_w_dictionary_items(self):the terminal shows AssertionError for the 4 operations
SUBFAILED(operation='addition') tests/test_calculator.py::TestCalculator::test_calculator_w_list_items - AssertionError: YZA.BCDEFGHIJKLMNO != 'BOOM!!!' SUBFAILED(operation='subtraction') tests/test_calculator.py::TestCalculator::test_calculator_w_list_items - AssertionError: PQR.STUVWXYZABCDE != 'BOOM!!!' SUBFAILED(operation='division') tests/test_calculator.py::TestCalculator::test_calculator_w_list_items - AssertionError: F.GHIJKLMNOPQRSTUV != 'BOOM!!!' SUBFAILED(operation='multiplication') tests/test_calculator.py::TestCalculator::test_calculator_w_list_items - AssertionError: WXYABC.DEFGHIJKLMN != 'BOOM!!!'I change the expectation
1 for operation in self.arithmetic_tests: 2 with self.subTest(operation=operation): 3 self.assertEqual( 4 self.arithmetic_tests[operation]['function']( 5 *two_numbers 6 ), 7 self.arithmetic_tests[operation]['expectation'] 8 )the test passes
I remove all the assertions for the starred expression
89 self.assertEqual( 90 src.calculator.subtract(two_numbers[-2], two_numbers[0]), 91 self.random_first_number-self.random_first_number 92 ) 93 94 for operation in self.arithmetic_tests: 95 with self.subTest(operation=operation): 96 self.assertEqual( 97 self.arithmetic_tests[operation]['function']( 98 *two_numbers 99 ), 100 self.arithmetic_tests[operation]['expectation'] 101 ) 102 103 def test_calculator_w_dictionary_items(self):still green
I add a for loop to
test_calculator_w_dictionary_items137 self.assertEqual( 138 src.calculator.subtract(**two_numbers), 139 self.random_first_number-self.random_second_number 140 ) 141 142 for operation in self.arithmetic_tests: 143 with self.subTest(operation=operation): 144 self.assertEqual( 145 self.arithmetic_tests[operation]['function']( 146 **two_numbers 147 ), 148 'BOOM!!!' 149 ) 150 151 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):the terminal shows AssertionError for the 4 operations
SUBFAILED(operation='addition') tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - AssertionError: OPQ.RSTUVWXYZABCDEF != 'BOOM!!!' SUBFAILED(operation='subtraction') tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - AssertionError: GHI.JKLMNOPQRSTUVWX != 'BOOM!!!' SUBFAILED(operation='division') tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - AssertionError: Y.ZABCDEFGHIJKLMNOP != 'BOOM!!!' SUBFAILED(operation='multiplication') tests/test_calculator.py::TestCalculator::test_calculator_w_dictionary_items - AssertionError: -QRSTU.VWXYZABCDEF != 'BOOM!!!'I change the expectation
142 for operation in self.arithmetic_tests: 143 with self.subTest(operation=operation): 144 self.assertEqual( 145 self.arithmetic_tests[operation]['function']( 146 **two_numbers 147 ), 148 self.arithmetic_tests[operation]['expectation'] 149 )the test passes
I remove the other assertions for the starred expression
121 self.assertEqual( 122 src.calculator.subtract(two_numbers['first_input'], two_numbers['first_input']), 123 self.random_first_number-self.random_first_number 124 ) 125 126 for operation in self.arithmetic_tests: 127 with self.subTest(operation=operation): 128 self.assertEqual( 129 self.arithmetic_tests[operation]['function']( 130 **two_numbers 131 ), 132 self.arithmetic_tests[operation]['expectation'] 133 ) 134 135 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):still green
close the project
I close
test_calculator.pyin the editorI click in the terminal and exit the tests with ctrl+c on the keyboard, the terminal shows
(.venv) .../pumping_python/calculatorI deactivate the virtual environment
deactivatethe terminal goes back to the command line,
(.venv)is no longer on the left side.../pumping_python/calculatorI change directory to the parent of
calculatorcd ..the terminal shows
.../pumping_pythonI am back in the
pumping_pythondirectory
review
I added the following tests for the calculator program with dictionaries which made testing the program easier
code from the chapter
what is next?
you know
rate pumping python
If this has been a 7 star experience for you, please leave a 5 star review. It helps other people get into the book too