|
|
Lab
2
This lab builds upon Lab 1. It continues to have a Station
class,
but there have been some changes made to it. Eventually there
will be a Customer class - not just yet, but there will be eventually.
The customer will have a location that is represented by
latitude
and longitude. The Station class in Lab 1 also had a location
represented by latitude and longitude. There really isn't a
difference in the location, both have a latitude and longitude.
The distance is calculated in the same manner. The
only
difference is that one is the location for a service station and one is
a location for a customer.
So,
since the instance fields are the same, the calculations are the same,
the decision is made to pull out the location and make it a class all
by itself. That way, both the Station and Customer classes
can
take advantage of it. If the location were to be left in both
classes, then there would need to be get/set methods in both classes,
the instance fields in both classes, and any other methods in both
classes. In other words, duplication of effort. By pulling it out and
making it its own class, all of
these items need to be written just once. Much more efficient!
Step
1
- read through the lab instructions in the Word document.
While
the scenario presented is for fun, there is some key information that
should be gleaned from the instructions.
- Creating a separate Location class:
- 2 instance fields
- improved calculation for distance between 2
locations - Great Circle Distance Formula
- previous calculation was in degrees, this will be
in radians, so first have to convert the latitude and longitude (in
degrees) to radians
- Great Circle Distance Formula is
calculated as:
- 3959.0 * arccos [ sin(lat1) * sin(lat2) +
cos(lat1) * cos(lat2) * cos(lon2 - lon1)]
- use Math.acos(), Math.cos(), Math.sin()
- 3959.0 is the approximate radius of the earth
in miles
- Changes to the Station class:
- instance variables:
- remove the instance variables latitude and
longitude and replace them with a Location object instance - default
values of 0.0
- fuel type - default value of 0
- description - default value of "NO DESCRIPTION
PROVIDED"
- price per gallon - default value of 0
- calcDistance will call the calcDistance method in
the Location class
- pricePerGallon method will have a new calculation
- the conversion factor is no longer 1.41, but is
instead:
- factor / (coeff1 * t + coeff2 * (100 - t))
- factor = 115400
- coeff1 = 756.7
- coeff2 = 1154
- t = type of fuel
- This conversion factor is multiplied by the price
per gallon
Step
2
- now let's take a look at the program documentation. The
javadocs have already been created for you in this project.
Javadocs provide a description of each method including the
purpose, what will be returned, if anything, and what explicit
parameters are to be provided, if any. This is really helpful
information that you will definitely want to check out before you begin
working on your test cases - which is what you should do BEFORE you
begin working on the program itself.
To generate the
documentation in BlueJ, select TOOLS, PROJECT DOCUMENTATION.
When you view the
documentation, you will see a listing for both of the constructors and
all of the methods. If you click on a constructor or method
name
you will be taken to that particular constructor or method where you
will be able to see a description of the method. You will
also be
shown what will be returned, if anything, and what explicit parameters
are expected if any. A description of each is provided.
This is really useful information and can guide you as you
develop your test cases and eventually start working on coding the
object itself.
Step
3a
Location Class
- Start
with the Location and testLocation classes. The Location
class
does not have any dependencies. What this means is that the
Location class does not rely upon any other classes in order to be able
to work. The Station class, on the other hand, does.
Because of the modifications that have been made, the Station
class now depends upon the Location class in order to be able to work.
Remember - longitude and latitude were replaced with a
Location
object. As a result, the Station class cannot be successfully
written and tested until the Location class is complete. In
object-oriented lingo this is a dependency. The Station class
depends upon the Location class.
Step
4a
- develop the test cases for the Location class. Open up the javadocs
for the Location class and open up the LocationTest class. If
you have a wide screen monitor, put the javadocs on one side and the
LocationTest class code on the other so that they are side by side and
you can see both at the same time.
Test the
constructor
- Viewing the javadocs tells you that there is one
Location constructor. This constructor is an explicit
constructor. It is expecting the latitude and longitude to be
passed to the constructor as explicit parameters.
- How should the constructor be tested?
- 1st
- create a Location object and make sure that it actually exists.
This is done by making sure the newly created object is not
equal
to null.
- 2nd - using the Location object you just created,
call the get methods for both the longitude and latitude and
make
sure that the value that is returned is what you are expecting.
- These will be set
equal to whatever values you pass in, so that is what should be
returned.
- If this method (it does not, but if it did) have a default constructor, this is how it would be tested:
/**
* Test object creation with
default constructor.
*/
public void testDefaultConstructor()
{
// create new instance & check that an object reference was
returned
Location location1 = new
Location();
assertNotNull(location1);
// test for default values using accessors
assertEquals(0.0,
location1.getLatitude(), 0.01);
assertEquals(0.0, location1.getLongitude(), 0.01);
}
- The
1st step from above is shown in green. A new Location object
is
created using the default constructor (notice the empty parenthesis).
Then the assertNotNull method is called which will return
true is
the newly created Location object is not null, meaning it has been
created and will return false if it is meaning that the object wasn't
created and so has failed the test.
- The 2nd
step from above is shown in blue. Because this is the default
constructor, the expectation is that both the longitude and latitude
have been set to a value of 0.0. So, the assertEquals()
method is
called with the first value saying what is expected, 0.0, and the
second value being what is actually there. The second value
is
provided by calling the get method for each.
- But
what is the 0.01? That is the delta value. Java
takes
double numbers out to insanely long decimal places. In order
for
the numbers to match you would have to match all of the decimals places
exactly. That is extremely tedious testing. So
instead you
can provide a delta value. What is says is that as along as
the
number are within .01 of each other - it's good enough - let's consider
them equal.
- for example, let's says that you are expecting
a value of 7.653, but when Java computed the value it came up with
7.6534683190555432. If you were just to compare these two
numbers
Java would fail the test - not equal - because of all those decimal
places. If, however, you provided a delta value of .001, Java
will only compare out to the 3rd decimal place and as long as those are
equal - then the test passes, good enough.
- To test the explicit constructor you will follow the same format as above:
- Create the object, calling the explicit constructor (passing in values for latitude and longitude)
- Assert that the object is not null (if it is null
then the object creation was unsuccessful)
- Check each of the instance variables to make sure
they contain the expected value.
- For
this second constructor, two explicit parameters are passed as part of
the object creation. You'll want to make sure that the
instance
fields contain their values after the constructor creates the object:
- verify that the latitude is equal to the value
you provided
- verify that the longitude is equal to the value
you provided
- These
values can be anything. You could provide 21.7 for the
latitude and
45.6 for the longitude. These might be a location in the
middle of the
ocean - but that's OK. You are aren't checking for a land
location,
just that whatever values you pass in as explicit parameters are being
stored in the instance variables.
Test the
set methods
- Testing the setLatitude() and setLongitude() methods
will be pretty much the same as for the constructors above.
- Create a Location object.
- Set the latitude/longitude to a new value.
- Use the assertEquals to compare the value returned
from the get method to what you are expecting.
Testing
the calcDistance() method
- The purpose of this method is to determine the
distance in miles between two locations. Remember a location
contains both a latitude and a longitude.
- Again, when testing this method the steps to take are
the same as those for the test cases above.
- Create a location object to be your initial
location.
- Create a second location object to be the new
location.
- Call the method.
- Check the result to make sure it is equal to what
you expect.
- Several test situations have been provided for you.
You are to write one more test case. To do so you
must first determine the latitude and longitude for a central Ohio
location.
- I wanted to use the latitude/longitude for Plain
City, Ohio, home of the Der Dutchman. I googled latitude and
longitude of Plain City Ohio and the following link came up:
- http://www.travelmath.com/
- On this site in the trip calculator you can set
the GET for latitude/longitude.
- You can then type in the name of a
town. I typed in Plain City Ohio.
- The latitude/longitude of Plain City Ohio was
then displayed.
- It was given as 40 degrees, 6' 27" N/83 degrees
16' 3" W
- Since I'm really only interested in the degrees,
I went with 40 for the latitude and -83 for the longitude.
- So - I would create a new location object,
perhaps with a name of plainCity and explicit parameters of 40.0 for
the latitude and -83.0 for the longitude.
- Next, I need to manually calculate the distance
from location 1 - which has a latitude of 39.95 and a longitude of -82.1
to my new location of latitude 40.0 and longitude -83.0.
- The formula for doing so was given in the word
document instructions. You can do this manually using a
calculator, using excel, or any other tool you might prefer.
When you can calculated the value you can then complete the
assertEquals() statement, following the format for the test cases
already in place for this method. **Remember, when doing your
calculation, don't round. The computer won't be rounding and
if you round you'll find that your result does not match the result of
the computer.
- *****An
excel spreadsheet has been provided for you to assist in developing
your test cases for this method. All you need to do is plug in
the latitudes and longitudes and it will calculate the distance for you.
Testing
the toString()
- This code has been provided for you, but it's a good
idea to review the code to ensure you understand how it is testing the
method.
- A
toString() method will be added to the Location class to provide both
the longitude and latitude in a particular format. Viewing
the
documentation for the Location class tells us that the format is:
Format
of the string should be
[latitude, longitude]
Example: [39.9571,
82.81]
- So,
the test case should make sure that value returned is indeed in this
format, with a starting [, then the latitude, then a comma, then a
space, then the longitude, and finally a closing ].
- How can this be tested?
- Follow the same format as above:
- Create a Location object using the first explicit
constructor (providing values for both the longitude and latitude)
- Use the assertEquals to compare the output from the
toString() method to what you are expecting.
- For example:
- If
you creating your location object using the values of 14.25 for the
latitude and 67.2 for the longitude then you would expect the output
from the toString() method to be "[14.25, 67.2]".
Step
5a
- code the Location class
- Now
that the test cases have been written, writing the Location class
itself becomes much easier. You are already familiar with the
methods because you have reviewed the documentation and have written
tests for them.
Instance
Variables
- These have already been coded for you.
There are 2 instance variables, latitude and longitude.
Both are of type double.
Constant
Variables
- One constant has been coded for you. This
contains the number 3959 which is the radius of the earth.
This constant will be used in the Great Circle Distance
Calculation.
Constructor
- The purpose of a constructor is to create the object
by initializing the values of the instance variables.
- You are to complete the code for the explicit
constructor. For this constructor explicit parameters have
been passed which contain the values the latitude and longitude are to
be set equal to.
get Methods
- A get method is an accessor method. It
accesses the values of the instance variables and returns their value.
- The code for the getLatitude() method is provided for
you. Use this as a guide for writing the code for the
getLongitude() method.
calcDistance() Method
- This
method will calculate the distance, in miles, between 2 specified
locations. This is NOT the same as what you coded in Lab 1.
This has a new calculation. The calculation is
provided for
you in the Word document as:
1.
First
convert
latitude and longitude (in degrees) to latitude and longitude in radians
NOTE: use the Math.toRadians method
2.
Use
the
formula
3959.0
*
arccos[ sin(lat1)
* sin(lat2) +
cos(lat1) * cos(lat2) * cos(lon2 - lon1) ]
Use
Math.acos,
Math.cos, Math.sin
3959.0 is the approximate radius of the earth in miles
- The references to latitude 1 and longitude 1 above,
refer
to the instance fields latitude and longitude. The references
to
latitude and longitude 2 above, refer to the Location that is passed in
to the method. (You will need to use the getLatitude() and
getLongitude() methods to retrieve these values)
- The
first step to take - before you can even begin with the calculation, is
to retrieve the latitude and longitude from the location that is passed
in as an explicit parameter. I would recommend putting these into
variables named lat2 and lon2 just so you can keep them straight.
Here's how this might look for the latitude.
- double lat2 = inLocation.getLatitude();
- You're
still not ready for the calculation - next you need to convert your
latitudes and longitudes from degrees to radians. This is done
with the Math.toRadians() method. Here's how this might look for
the latitude 1.
- double lat1 = Math.toRadians(this.latitude);
- Now you're ready to write the formula above.
toString() Method- Produce a string value in the format that is
specified in the method documentation. This code has been written
for you - but it's a good idea to review it to see how it is done.
After you get
a clean compile, run your test cases against the code. If a test
case fails, take a look at both the test case and the class code. Fix
the problem. Continue with this process until everything compiles
cleanly and all test cases run successfully.
Step
3b
Station Class
- Now that the Location class is written and tested, you are ready to start working on the Station class.
Step
4b
- develop the test cases for the Station class. Open up the javadocs
for the Station class and open up the StationTest class. If
you have a wide screen monitor, put the javadocs on one side and the
StationTest class code on the other so that they are side by side and
you can see both at the same time.
Test the
constructors
- The process for testing a constructor is the same, regardless of
whether it is an empty/default constructor or an explicit constructor.
- Call the constructor you are testing to create the object.
- Assert that the object is not null
- Check each of the instance variables to make sure they are equal to what you are expecting.
- The empty/default constructor test case has been written for you.
- Take a moment to review how this is done.
- You will be writing the test case for the explicit constructor. The process is the same as above:
- Call the explicit constructor, passing in values for
latitude, longitude, description, price, and fuel type. Check the
javadocs for the order of the parameters and the data types that are
expected.
- Asset not null to make sure the object has been created successfully.
- Call the get methods for each instance variable, making sure the value returned is what you specified in the constructor.
Test the set Methods
- The format for testing a set method is:
- Use a constructor, default or explicit, to create the object.
- Call the set method to set the instance variable to a new value.
- Call the get method to retrieve the value of the instance variable.
- Compare what is returned from the get method against what you used when setting the value to make sure they match.
- The
code for testing the description and fuel type is provided for you.
Use these as a model when writing the test case for the
setPricePerGallon().
Test the calcPricePerGGE() Method
- The format for testing - really no matter what you are testing is:
- Use a constructor, default or explicit, to create the object.
- Call a set method if needed.
- Call the method you are testing.
- Call the get method if needed.
- Compare what is returned against what you are expecting.
- For this method, the price per gallon and fuel type values factor into the calculation of price per GGE.
- One test case has been provided with a price per gallon of 2.13 and fuel type of 85.
- Call the set methods to set a different price per gallon and fuel type.
- Manually calculate what the price per GGE should be using paper/pencil, calculator, excel or any other tool you might prefer.
- Compare what you expect against what is returned using an assert statement.
Test the distanceInMiles() Method
- This
is really tested in the same way as the location method done above.
The test cases for this method are provided for you.
Test the toString() Method
- The
test cases for this method are provided for you. Please take a
moment to review so that you understand how it is tested.
Step
5b
- code the Station class
- Now
that the test cases have been written, writing the Station class
itself becomes much easier. You are already familiar with the
methods because you have reviewed the documentation and have written
tests for them.
- Documentation
- Take a moment, before you begin, to review the javadoc documentation
for this class. It can be viewed from BlueJ by,
Tools,
Project Documentation.
- This will show you the constructors
and all of the methods. From this documentation you will be
able
to determine if anything is returned and what explicit parameters are
expected.
- Coding - Look for the comments lines inserted
within the methods that tell
you that code should be inserted. This is where you will be
writing code. If you see a method that does not have any
comments
saying you should code, then please do not modify the method.
It
is correct as it is.
Instance
Variables
- These have already been coded for you.
There are 4 instance variables, description, pricePerGallon, fuelType, and a Location object.
Constant
Variables
- Three constants have been coded for you. These are used in the calculation of the price per GGE.
Constructors
- You will be writing the code for the default/empty constructor.
Remember the purpose of a constructor is to set the instance
variables equal to default values.
- the description should be set equal to "NO DESCRIPTION PROVIDED"
- the price per gallon should be set equal to 0.0
- the fuel type should be set equal to 0
- location
- this one is a bit different. You're not going to set it equal
to value, but rather create a location object passing in the default
values.
- If you take a look at the instance variable you'll see:
- private Location stationLocation;
- notice
there's no equal sign. What this means is that the object
variable has been defined as holding data type Location - but that it
hasn't yet been initialized. It doesn't contain anything.
If you were to try and access the contents of this variable you
would get an error.
- In the constructor you need to complete the
right hand side of the equals sign. You need to initialize your
object variable by calling the Location constructor.
- = new Location(0.0, 0.0);
- Now DO NOT do the following:
- Location stationLocation = new Location(0.0, 0.0);
- See
the data type Location? As soon as you put this in front of a
variable you end up with a local variable that exists only within the
method.
- Instead do:
- this.stationLocation = new Location(0.0, 0.0);
- This says to take the existing object variable and just assign it to a new Location object.
- Explicit Constructor - This has been coded for you. Take a moment to see how this was done.
get Methods()
- The purpose of a get method is to return the value of an instance variable.
- For the description, price per gallon, and fuel type it's very straight forward.
- For
the latitude and longitude - there's a slight twist. You can't
just return the latitude and longitude because they don't exist within
the station class itself. Instead you have to call the
getLatitude and getLongitude methods from the Location class. See
the getLatitude() method for an example of how this is done.
set Methods()
- The
purpose of a set method is to change the value of an instance variable.
An explicit parameter is passed to the method containing the
value that the instance variable should be set to.
- The format will be:
- this.instanceVariableName = passedInParameterName;
calcPricePerGGE() Method
- Use the formula provided in the word document to complete this method. Return the calculated value.
calcDistance() Method
- The
formula for calculating the distance between 2 locations was written in
the Location class. What you have to do here is call that method.
But.... the method is the location class is expecting a Location
object to be passed to it as an explicit parameter. If you take a
look at the explicit parameters passed to this method, however, you
have a latitude and longitude, not a Location class. So, the
first thing you need to do is create a temporary location object using
the passed in latitude and longitude.
- Then call the Location
object method using your Location instance variable as the calling
object and passing in your temporary location object as the explicit
parameter. Something like:
- return stationLocation.calcDistance(tmpLocation);
toString Method
- The code for this method has been completed for you. Please take a moment to review.
After you get
a clean compile, run your test cases against the code. If a test
case fails, take a look at both the test case and the class code. Fix
the problem. Continue with this process until everything compiles
cleanly and all test cases run successfully.
Step 6 - update the Readme.txt
file. Specific information is required to be entered into this
file. Make sure you view the instructions for this file so that
you do not lose points for an incorrect format.
Step 7 - use
the check style feature in BlueJ. This can be found under Tools,
Checkstyle. This tool will evaluate your program for style.
Each of the classes will be listed. Clicking on a class
name will reveal any style problems that have been found. These
would include such things as lines that are too long, incorrect
indentation, missing periods, etc. Correct all of these identified
problems. Recompile, retest. ****It is really important
that you do this. For each check style error found, webcat will
deduct 1 pt. These can really add up and you don't want to lose
points for things that can easily be corrected.
Step 8 - submit to WebCat.
This is not a one time submission. Webcat is a tool that
can be used to ensure you receive the maximum number of points possible. Submit, review the output. Make
corrections and submit again. Continue this process until you
have perfected your lab.
|