Objectives

A Calculator Application

In this lab you will develop the simple, text-based calculator shown below. As you design your application, it is a good idea to think about appropriate test cases during the analysis phase, before you design or implement your system. Then, you can retrieve and run these test cases in order to increase confidence that your design and implementation are correct. Because there are too may test cases to specify them all, it is important that you specify tests exercising the full range of the application’s functions.

a calculator application

Exercise 9.1

Make a short list of test cases that would exercise the calculator shown above. For example, if the calculator is working properly, then one plus one should equal two. Thus, you could add the following test case:

Add 5 to 6 test cases that exercise the limits of the calculator GUI you are designing and save them for use when you have the calculator implemented. For now, you can write them on a sheet of paper; you’ll implement them later.

As you can see from the design shown above, you must implement four text fields and a text label on the main control panel, placed on the “North” and one message label, placed on the “South”. Do this using containment properly, as shown in this diagram.

the GUI containment hierarchy

The class structure for your application is as follows.

calculator with GUI controller UML

As you can see, this application has no Processing-based panel. The Calculator class is purely a computational class that doesn’t inherit from any JFC/Swing class, doesn’t have any instance data, and uses an empty default constructor. It just calculates. That is, it is a model and the GUI is the view. Distinguishing the model and view during the design phase will be important when you get to unit testing. The GUI controller, CalculatorController, allows the user to enter values for the two operands and the operator, and then press enter to start the calculation. Here are algorithms for the CalculatorController class.

The Calculator class itself has one method that performs basic arithmetic calculations (i.e, addition, subtraction, multiplication and division). Here are algorithms for the Calculator class.

Exercise 9.2

Build classes for the Calculator and the CalculatorController as specified above. Make sure that this application can perform basic operations. Your instructor may provide the basic GUI code for you to start with.

Before moving on, find some ways in which users could break the application with inappropriate input. If you didn’t include test cases for these error conditions in your list of tests above, then add one test case for each error condition now.

Save these classes for use in the next exercise.

Exception Handling

The application you’ve developed so far does not handle anomalous user input appropriately. In this section, you add code to raise and handle exceptions properly.

Exercise 9.3

Add code in your Calculator class to throw an exception whenever the user (or calling program) specifies input that raises any of the following error conditions:

For the purposes of this lab, throw an Exception object (a checked exception), rather than the potentially more appropriate IllegalArgumentException (an unchecked exception). Using checked exceptions requires that calculate() either handle the exception or specify a throws clause. Use a throws clause for this exercise.

Save these classes for use in the next exercise. At this point, your controller class will have compilation errors because you haven’t yet handled the thrown exceptions; you will do this in the next exercise.

The methods called in your CalculatorController#actionPerformed() method are programmed to throw the following exception types:

You will need three catch blocks to handle these errors separately. Note that these catch blocks must be ordered as shown here, from most specific to most general (as specified in the Exception class hierarchy).

Exercise 9.4

Add exception handling code to your actionPerformed() method to handle the exceptions potentially thrown by the method calls it contains. Your GUI should display the error message in the messageLabel (using this command: messageLabel.setText(someMessageString)). You can do this by moving all your existing code in actionPerformed() into a try block, and then adding catch blocks for each of the exception types listed above.

Save your modified classes to turn in later.

Unit Testing

JUnit tests are implemented in a separate class that constructs and exercises a Calculator object (or Calculator objects). Go through the JUnit tutorial for your IDE:

You can find a complete API reference for all of the JUnit assert commands here: http://junit.org/apidocs/org/junit/Assert.html

You can visualize the class structure of your application with a JUnit test class as follows:

calculator UML with unit test class

If you took the wise step of specifying appropriate unit test cases during the analysis phase (see exercise 9.1), you can now implement those test cases without worrying that your tests will simply “confirm” your design and implementation rather than actually testing them. Note that you can only specify unit tests on the model class (i.e., Calculator), not on the view (CalculatorController). For example, you could test your addition calculation using the following test method:

@Test
public void calculateAdditionTest() {
	Calculator calculator = new Calculator();
	try {
		assertEquals(2.0, calculator.calculate(1, '+', 1), 1e-3);
	} catch (Exception exception) {
		fail("failed calculation unit test...");
	}
}
Exercise 9.5

Create a unit test class for the Calculator class and add test methods for each of the following cases:

Save this class to turn in later.

Checking In

Submit all the code and supporting files for the exercises in this lab.