The purpose of this assignment is to give you practice in a number of areas:
writing class definitions
thinking up tests for the methods that form part of the class definitions
using JUnit to write and run the tests
writing a moderate amount of Java (it will still seem like a lot, until you get used to it)
The classes that you write in this assignment don't "do" much - they are meant to represent a very simplified portion of the world (planes, runways and airport) according to the specifications below. Most of the "doing" is done by your test case classes: they test the methods of your other classes. The test case classes create objects of your other class types and invoke their methods to prove that the methods work properly.
The main purpose of the assignment is to get you to think about classes, objects, class (static) methods and variables, and object (instance) methods and variables, and to write them all out, along with the tests, to give you lots of practice in writing Java. Understanding the concepts is not difficult; one of the challenges is to translate the English description you are given below into Java in the first place. The other main challenge is getting everything right in Java - especially if you've never done it before. What the classes are all about is sometimes artificial and does not correspond to the real world - that's because this is an exercise, and some things are simplified to keep them doable.
To help you do the exercise right, this description goes into great detail. It will require several readings. Be sure to read ALL sections: The Task, Restrictions, What to Hand in, Marking, and the Hints section.
Start your assignment early; most people take much longer than they originally anticipate.
Read through early and often: as many times as necessary, to make sure you understand it.
If you are having difficulty understanding or doing the assignment: come and see an instructor or teaching assistant - but don't wait until the last minute; it's more difficult to provide help in an emergency.
For this assignment, you are asked to work with 6 classes:
Plane
, Runway
,
Airport
, PlaneTester
,
RunwayTester
and AirportTester
. As you can
see by their names, the
last three exist in order to test the first three.
An exact specification is given below for three of the classes:
Plane
, Runway
and Airport
.
That is, there is a description, in English, for every variable and
method that these classes are to have.
For the other three classes: PlaneTester
,
RunwayTester
and
AirportTester
, we give you general guidelines. We don't
provide exact instructions, but you can read here
about what to do with testing classes. There are also labs and
lectures that deal with testing and you should follow the examples
given there.
To help you start with the assignment, we provide you with the code for
Runway
class and RunwayTester
. So, you will
produce and submit the rest of 4 classes. However, we strongly recommend
not to look at the given code at the first place. Instead, try to write them
yourself (even a feeble attempt is way better than doing nothing and looking at the code). Then, compare what you have written with the given code to see
what's missing or needs improvment. After this, try to write the other 4 classes.
Consider an airport, with runways and planes. This assignment is about representing the planes and runways as objects with different properties described below, and simulating some of the operations of an airport. Planes have destinations or origins, take-off or landing schedules, and flight numbers. Planes are parked on runways. Planes taxi from one runway to another. Runways have directions, and they have planes parked on them.
An airport is a busy place. To keep things simple we are only going to keep track of one plane waiting to land and the planes on the runways (on the ground). Once a plane takes off or heads to the terminal it is no longer the program's concern.
Most airports have four runways that intersect approximately at right angles, two north-south and two east-west. Chicago's Midway Airport is a good example. While waiting to take off, planes taxi around the airfield from runway to runway. In our case, we will assume that they always taxi in a clockwise direction, that a runway holds only one plane at a time, and that it takes 3 minutes to taxi from one runway to the next.
Planes take off into and land into the wind. So one runway is designated as the active runway for take-off and landing. When a plane takes off or lands it creates turbulence. It takes time for the turbulence to dissipate and it is safe for the next plane to land or take off. In our case, we will assume that it takes a minimum of 8 minutes.
Here are the class descriptions:
Pay close attention to the tables below! There are two crucial things to remember:
Descriptions: while the descriptions given below are informal, they are precise and complete - everything is here, and well-defined;
Naming: you have to decide on your variable names, but your class must have exactly the constant and method names described in the tables - including the right letter case - and the methods must have exactly the parameters given: same order and same type, and must have the right return type as stated in the description. If you have to, use copy and paste for the method name, etc. from this page to get it right. (If you get it wrong, the assignment testing programs will not recognize your methods and you will get no credit for the methods.) As with the variables, we leave the parameter names up to you.
Plane
The Plane
class represents a plane. It has a number
of fields: the flight number, whether it is landing or taking off,
the expected time of take off or landing, and the destination or origin
of the plane.
Here are the definitions of the fields and methods of the Plane
class:
Type |
Description |
---|---|
|
The flight number of this plane. |
|
Whether the plane is landing or taking-off. |
|
The expected time of the landing or take-off. |
|
The location where the plane is taking-off to or landing from (i.e., the destination or origin of the plane). |
|
A |
Constructor |
Description |
---|---|
|
Constructor for the |
Method Name |
Description |
|
Return the flight number of this plane (as a |
|
Return the destination or origin of this plane (as a |
|
Return |
|
Set the time (in minutes) when this plane is expected to land or take-off. |
|
Return the time (in minutes) when this plane is expected to land or
take-off (as an |
|
A |
Runway
The Runway
class represents a runway at an airport.
The runway stores the direction of traffic on the runway, whether the
runway is occupied, and the plane that is currently on the runway.
The Runway
class has the following variables and methods:
Type |
Description |
---|---|
|
The direction of traffic on this runway (either East, West, North or South). |
|
Represents whether this runway is occupied by a plane: |
|
The plane currently on this runway (or |
|
Constructor for the |
|
Constructor for the |
Method |
Description |
---|---|
|
Return the plane on this runway (as a |
|
Set the plane on this runway to the given |
|
Return |
|
Set this runway to not occupied (if there is plane on the runway, it should be removed). |
|
Return the direction of traffic on this runway. |
|
Return |
Airport
This class represents an airport. It has a name, a city, four runways, a current time and several methods for setting and reading the values of these variables.
The Airport
class has the following variables and
methods:
Type |
Description |
---|---|
|
The name of the airport. |
|
The name of the city in which the airport is located. |
|
The eastbound runway. |
|
The westbound runway. |
|
The northbound runway. |
|
The southbound runway. |
|
The active runway for take-off and landing (one of the four runways above.) |
|
The current time (measured in minutes). |
|
The time when the active runway was last used (i.e., when a plane last took-off from or landed on the active runway) (measured in minutes). |
|
A plane that is in the air waiting to land (or |
Type |
Name |
Value |
Description |
---|---|---|---|
|
|
|
The safety interval between take off or landing planes (measured in minutes.) That is, the wait time between take offs and landings. |
|
|
|
The time it takes for a plane to taxi from one runway to the next (also this is the time it takes to taxi from the terminal to a runway, or from a runway to the terminal). |
|
|
|
The time it takes for a plane to land. |
|
|
|
The time it takes for a plane to take-off. |
Constructor |
Description |
---|---|
|
Constructor for the |
Method |
Description |
|
Return the name of this |
|
Return the name of the city the airport is in (as a |
|
Return the eastbound runway (as a |
|
Return the westbound runway (as a |
|
Return the northbound runway (as a |
|
Return the southbound runway (as a |
|
Return the active runway (the runway currently being
used for take-offs and landings) (as a |
|
Return the current time (as an |
|
Return the time when the active runway was last used or
0 if the runway has never been used
(as an |
|
Return the plane that is scheduled to land on the active
runway or |
|
Taxi each of the planes from one runway to the next clockwise (North to East, East to South, South to West, West to North). Adjust the current time to reflect the time that has passed (all planes are taxied simultaneously, so the elapsed time is the time to taxi one plane). |
|
Set the active runway (the runway currently being
used for take-off and landing) to the given |
|
Taxi a plane from the terminal to the given runway. The parameters are: the runway and the plane. (You may assume that the given runway is not occupied and the plane is at the terminal; we won't keep track.) |
|
Taxi a plane from a runway to the terminal (You may assume that there is a plane on that runway.) Update the status of runway. |
|
Set the given plan to be waiting to land at this airport. |
|
Returns a
|
|
Returns whether the plane on the active take-off and landing runway can take-off. There are two reasons why the plane would not be able to take-off:
|
|
Moves the waiting incoming plane to the take off/landing runway. This involves:
You may assume that this method will only be called when
the conditions described in |
|
The plane currently on the active take-off and landing runway takes-off. This involves:
You may assume that this method will only be called when
the conditions described in |
|
Return |
|
Return |
As a general rule, you can assume that all parameters have correct values, not null where not null are expected, positive where expected, etc. This means that your methods don't have to worry about these input values and your test classes don't have to test with them (we won't).
How do you know whether the Airport
, Runway
and Plane
classes you're designing are correct or not?
One way is if you test them, to see if they do
what they are supposed to do:
For each method that you add to Plane
,
Runway
and Airport
, you
are expected to write one or more test methods in
PlaneTester
,
RunwayTester
and AirportTester
classes, respectively. In these methods, you usually create at least
one new object and test your method on it.
The Test...
classes are the JUnit test suites you'll
design, which perform these testing tasks for you. Lectures and
tutorials will introduce you to JUnit - it comes with DrJava. You can
also get more detail by following the links on the course main
website's Java
links page.
Here are a couple of sample tests
for the classes; they should give you an illustration of what your
Test...
classes should do. Also, we have provided you with
RunwayTester
but as we mentioned above do not look at it
at the first place, instead try to write it yourself and then compare
your testcases with the given code.
Make sure that your test classes adhere to the following principles:
For each new method in a class,
your corresponding Test...
class should have at
least one test...
method that tests the new
method.
The more interesting a method is, the more test cases you should have for it. What makes a method 'interesting' can be the number of interesting combinations of inputs that a method can have, the number of different results that the method can have when run several times, the different results that can arise when other methods are called before and after this method, and so on.
Test very basic methods early in your test suite, and then move on to more complex ones. (This is the same as making sure that the parts of the car you are building work on their own before you take the whole car for a test drive.)
Remember that if you change static variables in an early test, they will retain their values in later tests.
Important: the tests in a JUnit test suite are not necessarily run in the order in which you list them in your suite. So when testing static variables, record their initial value at the beginning of the test, and test that the change in the value is what you expect.
You must not use if statements, loops and arrays. If you do, you will lose marks. (We leave those for later assignments.)
You will find that you can do everything you need to do with the
arithmetic operators (+, -) and boolean
operators (<,
<=, ==, =>, >, !=, &&
, ||
,
!
).
What is important? Several things. We do not hand out a detailed marking scheme, but here are the general outlines, and some explanatory notes:
The overall breakdown: correctness: 40%; commenting, style, testing: 60%.
Correctness: obviously, your classes and methods have to perform as specified. (In fact, your test suites will ensure this most of the time, but you may miss some test cases.) Correctness, as measured by our tests, will count for the largest single portion of your marks - but as you can see from the percentages above, you cannot pass on correctness alone.
Testing: as noted above, your test
classes should contain at least one test for each method on the
class being tested. The tests should be valid, cover different
situations, and organized. Test...
classes also need to be properly commented.
Commenting: your files should
contain a brief (one-sentence, usually) description of each class,
each variable, and each method (this includes your Test...
files). The descriptions must be in grammatical, clear English. The
specifications above are a good start - often what's there is just
what you need to write (or very similar). Remember, more is not
necessarily better.
Style: there are various aspects to style; in lectures and tutorials we'll cover some of the major points about formatting your files and about naming and spelling conventions. You are expected to satisfy those points.
Make sure that you read the Assignment rules page for some general rules and guidelines - there are more hints there about commenting and acceptable style.
The course website describes how you hand in your assignment. This section tells you what to hand in:
AirportTester.java
,
Airport.java
,
PlaneTester.java
,
Plane.java
.
Do NOT hand in
Runway.java
and
RunwayTester.java
(as we have already provided you with their solutions!).
Remember that spelling, including case, count in Java: your files must be named exactly as above.
NOTE: Other than the signoff statement,
only hand in the files that end with the .java
suffix. Be careful about this, because in the same place as your
.java
files you may also have files with the extension
.class
(that is, they end with the .class
suffix), but otherwise have the same name. Two particular pitfalls:
Microsoft operating systems often do not display file extensions unless they've been told to do so.
DrJava creates "backup files", which means that
you'll see filenames like "Plane.java~
".
Notice the ~
at the end. It indicates that the file is
a backup file, which happens to be an older version of your program.
Don't hand these in.
Since .class
files cannot be read by TAs or run with
our testing programs, submitting the wrong files might cause you to
fail the assignment. Every year, a half-dozen students submit the
wrong file; we simply cannot do anything to fix this mistake.
This is a large and complex assignment (for those who've never done anything like this before). It pulls together a number of things covered in lectures and labs: that is a lot of stuff. So here are a couple of pointers on how to go about this.
Read the assignment several times. When you think you have an idea
of what you are asked to do, start defining your first class. This should
be the
Runway
class so you can compare your attempts with the
solution provided. Write the class comment, then
the class header with an empty body. Compile. Write the variables and
add the comment that shows you know what each one is for. If you
can't write the comment, you may be having trouble understanding the
purpose of the variable. Compile.
Now write a header and empty body for the test class that tests the class. Compile.
Go back to the original class. Pick a simple method. Write the comment for the method and the method header, with an empty body.
If you understand what the method is supposed to do, then you should be able to write at least one test for the method in the test class, before you actually write the method.
Go back to the test class.
Write the test method. Usually this means creating an object of
the class being tested, then calling the method being tested, and
using one of the assert
methods to show that the method
did the right thing. (You may not be able to compile the test method
until after you write and compile the original method you are
testing, which is the next step.)
Write the original method body. Compile the class. Compile the test class.
Run the JUnit test. Fix any problems, re-run until the test passes. You may find that sometimes the problem is with the test method: make sure you're testing what you think you are testing.
You now have the skeleton of a class, and its test class!
Repeat with more methods: write the comments and the method header, write the test(s), then write the original method, compile and run the test. Fix the problems and move on. JUnit makes sure that the tests you wrote earlier are also performed, so you can see if you inadvertently introduced errors in methods you wrote earlier.
Keep working, back and forth, between a class and its test class. This is a useful approach: it makes sure that your classes work by testing them at every step, your tests are easier to define, because you have the method being tested fresh in your mind, and when you are done, both classes are written.
At first, this will seem very time-consuming. The good news is that it will get easier and faster the more you do it. Really. The only way to get better at it is to keep doing it.
If you're getting NullPointerException
reports and
would like to learn more about them, here is some background. (We
will not take marks off for these exceptions and reading this section
is optional.)
NullpointerException
s happen when Java is attempting
to excute an instruction which makes a reference to an object's
method or variable when that object's value is null
(the
object does not exist). The trick is to make sure to make the
reference only if the object exists.
The simplest way to do this would be with an if
statement - but we have not covered that yet; and besides, you are
not allowed to use if
in this assignment.
Hmmmm.
What we want to do is to prevent Java from calling a method or
evaluating a variable just in case the owner of that method or
variable happens to be null
. This is where you can be
clever and use the &&
operator:
When Java is trying to evaluate a boolean
expression
with this operator, it starts by evaluating the expression on the
left side of the operator first. If it finds that the left side is
, it will not bother to evaluate the
right side. For example, given
false
(a == b) && (c < d)
it will first check if a
is equal to b
.
If it is not, then this part is
, and
there is no point in seeing whether false
c
is less than d
:
the whole expression will be false
anyway.
So - without giving too much away - you can prevent Java from, for
example, calling a method on a null
object if you place
this method call as the second part of a &&
expression. The first part of the expression must be such that it is
false
if the object is null
: then the
second part will never be executed.