1 Lab Objectives
2 Testing methods that throw Exceptions
2.1 Adding Try/ Catch Blocks to Test Cases That Should Succeed
2.2 Writing Tests that Should Throw Exceptions
3 Creating Application: Writing Main Methods
4 If You Still Have Some Time ...
5 What to Turn in

Lab 5: Exceptions and Main Methods

1 Lab Objectives

This lab continues to work with the Banking System that we have been developing during lecture. Download the starter file and Main.java files to use in this lab.

2 Testing methods that throw Exceptions

Now that our methods can throw exceptions, we need to revise how we write test cases to catch and handle exceptions. There are two problems:

  1. methods that we are testing could throw exceptions, so Java reports compilation errors if we don’t handle them

  2. we want to test that exceptions are being thrown when we expect them to, which needs a different kind of test case.

We’ll look at each of these in turn.

2.1 Adding Try/Catch Blocks to Test Cases That Should Succeed

Open the Examples class in the starter file, and un-comment the test case in there. Try to run the test, and see the error that Java gives you.

To run this test, you need to add try-catch blocks as we did in lecture. Inside the test case, wrap the return statement in a try block. Outside the try block, catch a LoginFailedException (which is what the login method can throw). Inside the catch block, we want to report that the test failed in a way that the testing library will report it along with any other tests. Put the following code in the catch block:

  return t.checkExpect(false, "testValidLogin failed with exception");

When you use a boolean constant as the first argument to a checkExpect, the tester library will automatically report that test as failing (for false) or passing (for true). The string is the message that the tester library prints out to describe the test.

Once the test has the try/catch blocks, try compiling and running the test. Then make a "typo" in either the username or password in the test case. Run this so you can see what the failed test looks like through the library.

You will need this pattern to write your test cases for homeworks 5 and 6.

2.2 Writing Tests that Should Throw Exceptions

Now, let’s add a test case to the Examples class that calls the login method in the BankingService class with a customer name who is not in the system. The "expected answer" (second argument to the checkExpect) is an exception, but you can’t just put the exception there (since exceptions can prevent methods from finishing normally).

Instead, you use a new testing method called checkException. Here is an example.

Assume you wanted to test that

  B.login("Kathi", 123)

would raise a LoginFailedException. You would write:

  boolean testLoginExceptionOnUnknownUser(Tester t) {

    return t.checkException(new LoginFailedException(),

                            B, "login", "Kathi", 123);

  }

Note that instead of sending the method call as one argument, for checkException you break the call up into the object, the method name (as a string), and the arguments.

Why is this needed? When you put the method call as an argument to a checkExpect, Java runs the method before passing the result to the checkExpect function. But doing that will cause an exception which we need to catch and check for this test. You therefore give checkException the pieces of the method call to prevent the method you want to test from running before the tester library can put it into a try/catch block internally.

Make at least one more test case that should throw an exception (for example, using the wrong password for gompei. Don’t just copy/paste the current test case. Type it out afresh, as that will help you learn the pattern of writing such tests.

3 Creating Application: Writing Main Methods

Let’s switch gears a bit. What if you were trying to write an application in Java that you wanted to "start up" automatically when you ran it. Right now, we just run the tester automatically. In practice, you want to run the code, not the tests.

It’s time to understand the Main.java class.

Open the Main.java file. It has a class named Main which contains a method called main. When you run a Java application, Java requires some class to have a method named main with the following header:

    public static void main(String[] args) {

      // what to do when the program is run

  }

You’ve already seen public and void this term. The args parameter is how someone could pass information into your application when they start it off/open it from outside DrJava or Eclipse; its type is an array of strings. We haven’t discussed arrays, but for now you can think of them as a form of lists. Don’t worry about the static – for now just know that it has to be there.

In the main method we’ve used all term, we’ve had the line

  Tester.run(E)

where E is a new Examples object. The tester runs automatically when you run your program because this line is in the main class. In practice, you test applications while you are working on them, but once you are ready to release/share/publish your application, you turn off testing and just start the application when the program is run.

Let’s edit our main class to do that.

Comment out the line that starts the Tester library. Replace it with a line of code that will call the loginScreen method from the BankingSystem. We haven’t given you the exact code to write on purpose – try to figure out what you need to write here to call the loginScreen method. If you have it right, when you compile and run, you should be asked immediately to enter a username and password. If you make a mistake, you’ll be asked to re-enter this information.

If you get stuck in the login loop, you can hit the "Reset" button on DrJava or the "Stop" (big red) button in Eclipse to stop the program from running.

The Main class can contain whatever additional fields and methods you want, just like a normal class. In practice, you would also put any code to set up your objects and data in the Main class, rather than in the Examples class (which is just for testing). Copy whatever object-creation code you need over to the Main class, so that the Main class is self-contained and has no references to the Examples class. Compile and make sure you can run. Now you really have a standalone application that doesn’t include the testing component.

4 If You Still Have Some Time ...

The starter file still has the Accounts class returning null rather than throwing exceptions. Start working through the process of adding exceptions, as we did for finding Customers. You can work on throwing, catching, and testing exceptions for as far as you get in the remaining time.

5 What to Turn in

Submit all .java files that you produced for this assignment to the Lab5 area in InstructAssist.