Step Two
Now that we have completed the first item, the list looks like this:
- Invalid Input
- Addition
- Subtraction
- Multiplication
- Division
- Bracketed Expressions
We continue with handling invalid input. Whenever input is not a valid mathematical expression, the program shall show an error message. For this, we write a test case that checks several examples of invalid input.
def test_invalid_input(self): app = CalculatorApplication() output = app.calculate("+") self.assertEqual(output, "Invalid expression") output = app.calculate("3 +") self.assertEqual(output, "Invalid expression") output = app.calculate("5 * -") self.assertEqual(output, "Invalid expression") output = app.calculate("7 81") self.assertEqual(output, "Invalid expression")
Let’s run these two test. We expect the new test to fail. And it does.
FAIL: test_invalid_input (testCalculatorApplication.TestCalculatorApplication) ---------------------------------------------------------------------- Traceback (most recent call last): File ".../testCalculatorApplication.py", line 14, in test_invalid_input self.assertEqual(output, "Invalid expression") AssertionError: '0' != 'Invalid expression' - 0 + Invalid expression ---------------------------------------------------------------------- Ran 2 tests in 0.001s
The test is right – the current implementation of calculate always returns “0”, which makes this test fail. To make the test pass, we have to distinguish between an empty input and an invalid input. What makes up an invalid input? Let’s fake it by doing the simplest solution: An empty string is valid, a non-empty string is invalid. This will make the tests pass. We will do the real implementation in a later step when we add the first test for valid input.
class CalculatorApplication(): def calculate(self, expression): if(expression == ""): return "0" else: return "Invalid expression"
This simple implementation makes both tests green. Next comes the refactoring phase.
There is some duplication in the unit tests. Both tests create an instance of CalculatorApplication to use for the test. This can be done in a setUp method, so the code only appears once. The method setUp will be called by the test framework before each test. With our implementation of setUp, each test will have a freshly prepared instance of CalculatorApplication.
import unittest from CalculatorApplication import CalculatorApplication class TestCalculatorApplication(unittest.TestCase): def setUp(self): self.app = app = CalculatorApplication() def test_empty_input(self): output = self.app.calculate("") self.assertEqual(output, "0") def test_invalid_input(self): output = self.app.calculate("+") self.assertEqual(output, "Invalid expression") output = self.app.calculate("3 +") self.assertEqual(output, "Invalid expression") output = self.app.calculate("5 * -") self.assertEqual(output, "Invalid expression") output = self.app.calculate("7 81") self.assertEqual(output, "Invalid expression")
Summary of Step Two
We have written a new test case and added some functionality. Also, we have done the first refactoring. To make the test pass we cheated a little bit. This cheat will be removed in the next step.
As this step is over, let’s cross “Invalid Input” of the list.