HW2: Duke-n-Donuts v2¶
Learning Objectives¶
- Identify the difference between static and non-static members.
- Develop a small library that can be used to support unit testing.
- Compare variables and analyze the impact of their data types on comparisons.
Note
Before proceeding with this assignment, open Checkstyle.xml
in the CS159/.vscode
folder in VS Code and replace line 146 with the following statement:
value="[/\\](acts|edu|exams)[/\\]|([^/\\]+Test|Test[^/\\]+)\.java$"/>
Overview¶
The former JMU students that opened Duke-n-Donuts have decided to sell other products (e.g., cookies, cupcakes) and this has made them realize that their original design for the pricing system was bad. In particular, they realize that if they were to continue with the current design they would need to have a utility class for each product (e.g., a DonutPricer
, a CookiePricer
, a CupcakePricer
, etc.), and that each of these classes would be very similar (and, hence, contain duplicate code). So, they have changed the design so that they can have an object for each product rather than a utility class for each product.
For example, with the old design, if Duke-n-Donuts sold donuts and cookies they would need two almost identical utility classes and would use them as follows:
double total;
total = DonutPricer.priceFor(6) + CookiePricer.priceFor(50);
With the new design they will need only one class and will use it as follows:
double total;
Pricer donuts, cookies;
donuts = new Pricer(12, 9.99, 0.99);
cookies = new Pricer(36, 17.99, 0.75);
total = donuts.priceFor(6) + cookies.priceFor(50);
The Classes to be Written¶
You must write a "normal" class named Pricer
and a utility class named Test
. The Pricer
class is specific to stores like Duke-n-Donuts. The Test
class can be used to test classes that are written for many different kinds of products.
The Pricer
Class¶
A Pricer
object can be used to price any item that can be sold individually or in boxes.
The UML Class Diagram¶
The following UML class diagram provides an overview of the attributes and methods in this class (which must be in the default package).
Notice that there are several important differences between this "normal" class and the utility class from the previous assignment.
- All of the attributes are now non-static and, so, belong to individual objects in the class rather than the class itself.
- The attributes are now initialized in an explicit value constructor.
- The methods are now non-static and, so, make use of the non-static attributes (that have different values for each object in the class).
Detailed Design Specifications¶
- The constructor must initialize the attributes of the object.
- The other methods must conform to the specifications for the DonutPricer class, but must work for anything that can be sold in boxes or individually (not just donuts).
Note that the official tests for the DonutPricer
class did not necessarily test that your submission satisfied all of the specifications. So, you may think your code was correct when it wasn't. Make sure you read all of the specifications for this assignment.
The Test
Class¶
The Test
class is a utility class that can be used to simplify the process of testing other classes. Such a system is sometimes referred to as a test harness or a testing framework. This class must conform to the course style guide (because it is not a test, it is a test harness.)
The UML Class Diagram¶
The following UML class diagram provides an overview of this class (which must be in the default package).
Detailed Design Specifications¶
In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.
forEqualDoubles()
must check to determine if the attributesexpected
andactual
differ by more than thetolerance
.- If so, it must return
false
and print the values ofdescription
,expected
, andactual
(in that order) using the formatString
"%s Expected: %f, Actual: %f\n"
. - If not, it must return
true
(and not print anything).
- If so, it must return
forEqualInts()
must check to determine if the attributesexpected
andactual
differ.- If so, it must return
false
and print the values ofdescription
,expected
, andactual
(in that order) using the formatString
"%s Expected: %d, Actual: %d\n"
. - If not, it must return
true
(and not print anything).
- If so, it must return
forEqualStrings()
must check to determine if the attributesexpected
andactual
differ.- If so, it must return
false
and print the values ofdescription
,expected
, andactual
(in that order) using the formatString
"%s Expected: %s, Actual: %s\n"
. - If not, it must return
true
(and not print anything).
- If so, it must return
forFalse()
must check to determine if the attribute namedactual
isfalse
- If so, it must return
true
(and not print anything). - If not, it must return
false
and print thedescription
using the formatString
"%s Expected: false, Actual: true\n"
.
- If so, it must return
forTrue()
must check to determine if the attribute namedactual
istrue
- If so, it must return
true
(and not print anything). - If not, it must return
false
and print thedescription
using the formatString
"%s Expected: true, Actual: false\n"
.
- If so, it must return
For example, one might implement the forEqualInts()
method as follows:
/**
* Display an alert if the actual int value is not equal to the
* expected value.
*
* @param expected The expected value
* @param actual The actual value
* @param description A description of the test
* @return true if the two are equal; false otherwise
*/
public static boolean forEqualInts(int expected, int actual,
String description) {
if (expected != actual) {
System.out.printf("%s Expected: %d, Actual: %d\n",
description, expected, actual);
return false;
} else {
return true;
}
}
An Existing Class¶
A main class (i.e., a class with a main()
method) that you can use to test the Pricer
class has already been written. It is named PricerTest
and the source code (i.e., the .java
file) is available at:
Unlike the DonutPricerTest
class from the previous assignment, this class makes use of the Test
class that you have to write. So, you will not be able to test your Pricer
class until you write the Test
class.
Like the DonutPricerTest
class, this class does not conform to the style guide. As mentioned before, most organizations (including most faculty in the Computer Science Department at JMU) do not require that tests conform to the style guide.
Submission¶
You must submit (using Gradescope):
- Your implementation of the
Pricer
class and your implementation of theTest
class. Do not include thePricerTest
class.
There is no limit on the number of submissions and no penalty for excessive submissions. Note that your submission will not be graded if it does not comply with the specifications. So, your submission should include a stubbed-out version of all of the classes. (This will allow you to get credit for the classes/methods that you do implement correctly.)
Grading¶
Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment
Gradescope Grading¶
Your code must compile (in Gradescope, this will be indicated in the section on "Does your code compile?") and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on "Do your class names, method signatures, etc. comply with the specifications?") for you to receive any points on this assignment. Gradescope will then grade your submission as follows:
Criterion | Points | Details |
---|---|---|
Conformance to the Style Guide | 20 points | (Partial Credit Possible) |
Correctness | 80 points | (Partial Credit Possible) |
Gradescope will provide you with hints, but may not completely identify the defects in your submission.
Manual Grading¶
After the due date, the Professor may manually review your code. At this time, points may be deducted for inelegant code, inappropriate variable names, bad comments, etc.
Recommended Process¶
Since nobody will be looking over your shoulder, you can use any process that you would like to use. However, it is strongly recommended that you use the process described here.
Get Started¶
- Read and understand the entire assignment.
- Create a folder for this assignment named
hw2
(undersrc/hws
). - Download
PricerTest.java
to a directory outside of yourCS159
folder (e.g., the downloads directory for this course).
Understand the Test Cases¶
- Read and understand the test cases in
PricerTest.java
. - By hand (i.e., using pencil and paper), calculate the expected answer for each of the test cases in
PricerTest.java
.
Copy and Rename DonutPricer.java
¶
- Copy
DonutPricer.java
from the folder namedhw1
to the folder namedhw2
. - In VS code, rename
DonutPricer.java
toPricer.java
. (Hint: Right-click on the file name and select [Rename…].)
Make Pricer.java
a "Normal" Class¶
- Delete the initialization of all of the attributes (and save the file).
- Understand why this generated several syntax errors.
- Remove the
final
modifier from all of the attributes (and save the file). - Understand why this resolved the syntax errors.
- Make all of the attributes non-static (i.e., remove the
static
modifiers). - Understand why this generated several style errors.
- Understand why this also generated several syntax errors in the methods that follow.
- Rename the attributes (and save the file). (Hint: Highlight the attribute identifier, right-click on the highlighted identifier, pull down to [Refactor], and then across to [Rename…], type the new identifier, and press [Enter]. Notice that this changes the identifier everywhere in the class.)
- Understand why this resolved the style errors.
- Remove the
static
modifier from all of the methods (and save the file). - Understand why this resolved the syntax errors.
- Write the explicit value constructor.
Stub-Out the Test
Class¶
- Create a version of the
Test
class that contains all of the methods (with appropriate signatures), each of which should returnfalse
. - Add the "javadoc" comments to the
Test
class and the methods in it. - Check the style of the
Test
class and make any necessary corrections.
Add PricerTest.java
to the hw2
folder¶
- Add
PricerTest.java
to thehw2
folder. - Make sure there are no compile-time errors in
PricerTest.java
. If there are, you probably need to fix the stubbed-out version ofTest.java
(since there should be no syntax errors inPricerTest.java
).
Implement the Test
Class¶
- Add the
forEqualInts()
method. (Hint: See the example above.) - Add the
forEqualStrings()
method. (Hint: Be careful about how you compareString
objects.) - Add the
forEqualDoubles()
method. (Hint: You should probably use the staticabs()
method in theMath
class.) - Add the other methods.
Test and Debug the Pricer
Class¶
- Run
PricerTest
. - If there is any output it means that your code failed a test. Starting with the first failure, debug the relevant method in the
Pricer
class using the process we discussed. - Re-run
PricerTest
and repeat as necessary.
Questions to Think About¶
You don't have to submit your answers to these questions, but you should try to answer them because they will help you determine whether or not you understand some of the important concepts covered in this assignment.
- Notice that the
PricerTest
class now uses an array for the input values and uses a loop to run all of the test. Why is this better than the approach used in the previous assignment? - How could you change the
PricerTest
class so that it keeps a count of the number of failed tests (and reports that number)? - What compile-time errors are generated in the
Pricer
class if you make the attributes in itstatic
? Why? - Why does the
PricerTest
class test thedounutPricer
again after testing thecookiePricer
? In other words, what defects might this re-test identify? (Hint: Think about your answer to the previous question.) - Why would it be nice to be able to overload methods in the
Test
class?