Hint: If this is your first time writing tests with JUnit, see writing JUnit Tests in Java under miscellaneous.
The goal of this lab is to provide you with an overview of fundamental concepts in object-oriented programming, which is a prerequisite to understanding and applying design patterns.
Video
Objectives
In this lab you will
- apply fundamental concepts in Object-Oriented Programming.
- understand when to use instance and class variables.
- write unit tests and apply Test-Driven Development (TDD).
- use inheritance appropriately.
- effectively utilize inheritance and polymorphism.
- apply key object-oriented concepts such as abstraction and encapsulation.
Requirement and Tools
- Java JDK 8 or above.
- An IDE (e.g., Apache NetBeans, Eclipse or IntelliJ IDEA).
- If you do not like to use an IDE, you may use any text editor (e.g., VS Code, jEdit, etc.) and the Javac compiler.
- The unit testing framework, Junit 4.
Getting Started
If your instructor is using GitHub classroom, you will need to accept the assignment using the link below, clone the template repository, and import it as a project into your IDE.
If your instructor is not using GitHub classroom, clone and import the template project at https://github.com/cpit252/lab-01.
1. Instance and class variables
Count that does not work
Consider the following Java code:
Product.java
public class Product {
private int id;
private double price;
private String name;
private int quantity;
public Product(int id, double price, String name){
this.id = id;
this.price = price;
this.name = name;
this.quantity ++;
}
public void applySaleDiscount(double percentage){
this.price = this.price - ((percentage/100) * this.price);
}
public void addToShoppingCart(){
System.out.println(this.name + " has been added to the shopping cart.");
}
public int getTotalQuantity(){
return this.quantity;
}
public void getSellableStatus(){
System.out.println("This product is sellable");
}
public String toString(){
return "Product info:\n+Id: " + this.id + "\t" + "name: " + this.name +
"\tPrice: SR" + this.price;
}
}
and the following client program:
App.java
public class App{
public static void main(String[]args){
Product p1 = new Product(6745, 5.50, "Penne Pasta");
Product p2 = new Product(8853, 6.50, "Spaghetti Pasta");
Product p3 = new Product(2106, 4.50, "Linguine Pasta");
System.out.println("Total Quantity: " + p3.getTotalQuantity());
}
}
When compiling this code and running it:
javac *.java
java App
We get the following output:
Total Quantity: 1
Question: How would you fix this code to print the correct total quanitity, 3?
2. Testing
A unit test is a piece of code that executes a specific functionality in the code to be tested and ensures it behaves as intended. This will help you in the future when additional changes are made to the code.
To add Junit 4 to your project, edit the pom.xml
file and add the following:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
Question: Complete the following unit test for the previous problem to ensure that the code always returns the correct quantity.
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ProductTest
{
@Test
public void shouldCountQuantity()
{
Product p1 = new Product(6745, 5.50, "Penne Pasta");
Product p2 = new Product(8853, 6.50, "Spaghetti Pasta");
Product p3 = new Product(2106, 4.50, "Linguine Pasta");
assertEquals(p3.getTotalQuantity(), 3);
}
}
3. Inhertiance
Extend the product class by adding the following two derived classes (a.k.a child classes and subclasses):
public class ElectricProduct extends Product{
private String voltage;
public ElectricProduct(int id, double price, String name, String voltage){
super(id, price, name);
this.voltage = voltage;
}
@Override
public String toString(){
return super.toString() +"\t Voltage: " + this.voltage;
}
}
import java.time.LocalDate;
public class FoodProduct extends Product{
private LocalDate expirationDate;
public FoodProduct(int id, double price, String name, LocalDate expirationDate){
super(id, price, name);
this.expirationDate = expirationDate;
}
@Override
public String toString(){
return super.toString() +"\t Expiration Date: " + this.expirationDate;
}
}
And add the following main/client class:
import java.time.LocalDate;
public class App{
public static void main(String[]args){
Product p = new Product(1234, 9.99, "water");
FoodProduct p4 = new FoodProduct(3452, 10.0, "Cheddar Cheese",
LocalDate.parse("2022-06-07"));
ElectricProduct p5 = new ElectricProduct(4875, 30.0, "Extension cord", "220v");
}
}
Question: The Product class should not be instantiated directly as done in the first line of the main method. Change the Product class, so only concrete classes should be instantiated. What changes would you make?
4. Polymorphism “Many Forms”
Question: Change the main class to utilize the use of Polymorphism and iterate through an array of Products
using the enhanced for statement (a.k.a For-Each Loop)?
for(Product p: products){
}
5. Controlling Changes
Question: What would you do to prevent subclasses from overriding the addToShoppingCart()
method of the Product
class without changing its visibility?
6. Abstraction
We decided to add a feature to the Product
class by adding Order information:
public class Product {
private int id;
private double price;
private String name;
private int quantity;
private int orderId;
private String orderStatus;
public Product(int id, double price, String name, int orderId, String orderStatus){
this.id = id;
this.price = price;
this.name = name;
this.orderId = orderId;
this.orderStatus = "created"
this.quantity ++;
}
Question: Why is this considered bad? How would you fix it?
7. Encapsulation
We decided to add a feature to the Product
class by adding the product’s weight
information. We decided to make it public, so any subclass can change it easily.
public class Product {
private int id;
private double price;
private String name;
public double weight;
public Product(int id, double price, String name, int orderId, String orderStatus){
this.id = id;
this.price = price;
this.name = name;
this.orderId = orderId;
this.orderStatus = "created"
this.quantity ++;
}
Question: Why is this considered bad? How would you fix it?