JUnit Tests with classes that rely on other classes - java

Hi i have this class Item
public class Item implements Cloneable {
private String name;
private int reorderAmount;
public Item(String name, int reorderAmount) {
this.name = name;
this.reorderAmount = reorderAmount;
}
/**
* #return The Amount of a reorder.
*/
public int getReorderAmount() {
return reorderAmount;
}
}
My other class is Stock
public class Stock extends HashMap {
private HashMap<String, Item> stock;
/**
* Constructor. Creates a stock.
*/
public Stock() {
stock = new HashMap<>();
}
/**
* Calculates the total Quantity of Items for the next Order.
* #return Number of total reorder quantity.
*/
public int getTotalReorderAmount() {
int reorderQuantity = 0;
for (Item item : (Collection<Item>) this.values()) {
reorderQuantity += item.getReorderAmount();
}
return reorderQuantity;
}
}
I'm having trouble running my JUnit test as my understanding on how one class effects another is lacking.
public class StockTests {
Stock stock;
Item item;
// Clear the item and stock object before every test
#Before
public void setUp() {
String name = "bread";
Integer reorderAmount = 100;
item = new Item(name, reorderAmount);
stock = null;
}
/*
* Test 1: Test the total number of items needed.
*/
#Test
public void testReorderAmount() {
stock = new Stock();
assertEquals(100, stock.getTotalReorderAmount());
}
}
What I have currently done is created an Item 'bread' inside the #before of my Junit testing class with 100 as the reorder amount. I am testing to see if my method getTotalReorderAmount inside my Stock Class is returning 100 however my JUnit results tell me it is returning 0. This is where i believe that i am creating the Item incorrectly within the JUnit Class.

You create an item, but never add it to the Stock.
A simplistic implementation:
public class Stock {
....
public void add(Item item) {
stock.put(item.getName(), item);
}
}
Your test could be:
/*
* Test 1: Test the total number of items needed.
*/
#Test
public void testReorderAmount() {
Stock stock = new Stock();
stock.add(new Item("bread", 100));
assertEquals(100, stock.getTotalReorderAmount());
}
No need to use setUp in this case.
By the way, the most basic testcase (which is advisable to start with) is the empty stock:
#Test
public void emptyStock() {
Stock stock = new Stock();
assertEquals(0, stock.getTotalReorderAmount());
}

In your testReorderAmount method, you have to set item you created.
Firstly modify your Stock class to have a method which adds item in private HashMap<String, Item> stock.
i.e. you class Stock could look like:
public class Stock {
.............
private HashMap<String, Item> stock;
public void addItemToStock(String itemName, Item item){
stock.put(itemName, item);
}
/**
* Constructor. Creates a stock.
*/
public Stock() {
stock = new HashMap<>();
}
.........
}
Secondly, set the item inside the stock map in your junit test.
Your test method will look like :
/*
* Test 1: Test the total number of items needed.
*/
#Test
public void testReorderAmount() {
stock = new Stock();
stock.addItem("bread", this.item);
assertEquals(100, stock.getTotalReorderAmount());
}

Related

Using strategy pattern along with Dependency injection

I'm going through Strategy pattern listed out in https://en.wikipedia.org/wiki/Strategy_pattern and trying to understand how this would work when you want to use Dependency injection as well and make it easy for unit testing.
So the interface is:
interface BillingStrategy {
// Use a price in cents to avoid floating point round-off error
int getActPrice(int rawPrice);
}
There are two implementations:
#Component
NormalHours implements BillingStrategy {
public int getActPrice(int rawPrice) {
return rawPrice;
}
}
#Component
HappyHours implements BillingStrategy {
public int getActPrice(int rawPrice) {
return rawPrice/2;
}
}
Now there is a customer object for whom I want to keep track of how the total price:
class Customer {
private final List<Integer> drinks = new ArrayList<>();
private BillingStrategy strategy;
public Customer(BillingStrategy strategy) {
this.strategy = strategy;
}
public void add(int price, int quantity) {
this.drinks.add(this.strategy.getActPrice(price*quantity));
}
// Payment of bill
public int getBill() {
int sum = this.drinks.stream().mapToInt(v -> v).sum();
this.drinks.clear();
return sum;
}
// Set Strategy
public void setStrategy(BillingStrategy strategy) {
this.strategy = strategy;
}
}
Now say I've a file which I've which has information about purchases made during each hour of the day, and I need to compute the final bill for the customer.
#Component
public class Calculator {
public int calculate(File file) {
//pseudo code here
Customer customer = new Customer();
for(line in file) {
//parse price, strategy and quantity from line
customer.setStrategy(strategy);
customer.add(price, quantity);
}
return customer.getBill();
}
}
Obviously this doesn't work great for unit testing as a new object is created within the method and by using just regular Mockito it's going to be hard to mock the values returned for the strategies in Calculator class. Is there a different way to model the Customer & Calculator class to ensure ease of testing and use DI as much as possible?
I know one way is let the caller of Calculator pass in the object Customer, but however with the way the wiki has explained this particular Customer class we cannot make it as a Singleton and the same problem will exist.
Given strategy isn't related to the Customer itself and placing it inside Customer is DI violation. Instead just pass strategy as method argument
class Customer {
private final List<Integer> drinks = new ArrayList<>();
public void add(BillingStrategy strategy, int price, int quantity) {
drinks.add(strategy.getActPrice(price * quantity));
}
// Payment of bill
public int getBill() {
int sum = drinks.stream().mapToInt(v -> v).sum();
drinks.clear();
return sum;
}
}
#Component
public class Calculator {
public int calculate(Customer customer, File file) {
//pseudo code here
for(line in file) {
//parse price, strategy and quantity from line
customer.add(strategy, price, quantity);
}
return customer.getBill();
}
}

Constructor Item in class Item cannot be applied to given types; [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
So I am very new to Java... been at it for about 4 weeks... be gentle.
I am trying to get my takeItem method (below) to pass the itemName variable back to my Player Class so I can add an item from my current room to my player. I get the compiler error: Constructor Item in class Item cannot be applied to given types..
my end goal is to get the player class to hold the object after removing it from the room.
takeItem Method:
private void takeItem(Command command)
{
if(!command.hasSecondWord()) {
// if there is no second word, we don't know where to go...
System.out.println("Take what?");
System.out.println();
return;
}
String itemName = command.getSecondWord();
Item theItem;
// Try to take an item.
theItem = new Item(player.getCurrentRoom().removeItem(itemName));
if (theItem == null)
{
System.out.println("There is no item!");
}
else
{
player.addItem(theItem);
player.getItemsCarried();//print item info
}
Player Class:
//above code omitted//
public void setCurrentRoom(Room room)
{
currentRoom = room;
}
public Room getCurrentRoom()
{
return currentRoom;
}
//code below omitted//
public void addItem (Item thingy)
{
items.put(thingy.getName(), thingy);
}
//code below omitted//
Item Class:
public class Item
{
// instance variables - replace the example below with your own
private String name;
private String description;
private int weight;
/**
* Constructor for objects of class Item
*/
public Item(String n, String d, int w)
{
name = n;
description = d;
weight = w;
}
//code below omitted//
Room Class:
public class Room
{
private String description;
private HashMap <String, Room> exits;
private HashMap <String, Item> items;
//some code below omitted//
public Room (String description)
{
this.description = description;
exits = new HashMap<>();
items = new HashMap<>();
}
public void addItem (Item thingy)
{
items.put(thingy.getName(), thingy);
}
public String removeItem(String thingy)
{
items.remove(thingy);
return thingy;
}
//code below omitted
Your constructor in the Item class takes two String parameters and one int, but you are trying to create a new Item by passing in only one String (whatever is returned by the removeItem() method). You can either change the removeItem() method so that it returns the Item that is removed, in which case you should change
theItem = new Item(player.getCurrentRoom().removeItem(itemName));
to
theItem = player.getCurrentRoom().removeItem(itemName);
or you can create a new Item with the necessary parameters.

Q: How to print a specific field of a specific row from my TableView?

i have the following problem: I read out database items in an observable list. Now I want to display some items from the selected line in a few textfields on the right side of my tableview.
I got the observable-line-index with the following code, but I want to select an other column of the line.
AnalysemethodenTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>() {
public void changed(ObservableValue<?> observable, Object oldvalue, Object newValue) {
index.set(analysemethodendata.indexOf(newValue));
databaseIndex = (analysemethodendata.indexOf(newValue) + 1);
System.out.println("Index:\t" + databaseIndex);
}
});
I found the following code: Click
But i don't understand this. It's something like to write a new list and place a copy of the items of the observable list in this new list.
I think, if I have the index of the line with my code, I can select the other items in the line of the observable list, too (I thought like "x,y" like an array)
If i cast it to String, the output is only machine code.
Hope I can understand the solution with your help!
EDIT: I inserted the following code:
System.out.println(analysemethodendata.get(databaseIndex).toString());
But I only get machine code in my Output:
table.analysemethoden_table#63c0d5b7
EDIT 2:
Table-Controller-Code:
package table;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleStringProperty;
public class analysemethoden_table {
private final SimpleStringProperty rAmnorm;
private final SimpleStringProperty rMethverantw;
private final SimpleFloatProperty rBestimmungsgrenze;
private final SimpleFloatProperty rNachweisgrenze;
public analysemethoden_table (String sAmnorm, String sMethoverantw, Float sBestimmungsgrenze, Float sNachweisgrenze) {
this.rAmnorm = new SimpleStringProperty(sAmnorm);
this.rMethverantw = new SimpleStringProperty(sMethoverantw);
this.rBestimmungsgrenze = new SimpleFloatProperty(sBestimmungsgrenze);
this.rNachweisgrenze = new SimpleFloatProperty(sNachweisgrenze);
}
// Getter- und Setter-Methoden
/** rAmnorm **/
public String getRAmnorm() {
return rAmnorm.get();
}
public void setRAmnorm(String set) {
rAmnorm.set(set);
}
/** rMethverantw **/
public String getRMethverantw() {
return rMethverantw.get();
}
public void setRMethverantw(String set) {
rMethverantw.set(set);
}
/** rBestimmungsgrenze **/
public Float getRBestimmungsgrenze() {
return rBestimmungsgrenze.get();
}
public void setRBestimmungsgrenze(Float set) {
rBestimmungsgrenze.set(set);
}
/** rNachweisgrenze **/
public Float getRNachweisgrenze() {
return rNachweisgrenze.get();
}
public void setRNachweisgrenze(Float set) {
rNachweisgrenze.set(set);
}
}
You need to use
analysemethodendata.get(databaseIndex).getRAmnorm();
or any other getter method in place of getRAmnorm() to get the required output.
databaseIndex -> row number

Cannot make static reference to non-static object

This is my first Java project.
So I'm working on my own simulation project, and some of my core stuff has gone awry. I have two classes I'm focusing on right now - settlement and townRey, which extends settlement.
The error is thrown when I try
System.out.println(townRey.returnStrength());
Here are my two relevant classes:
settlement:
public class settlement
{
//
//
// VARIABLES
//
//
/**
* The town's unique name.
*/
public String name;
/**
* The settlement's location in latitude (N-S)
*/
public int latitude;
/**
* The settlement's location in longitude (E-W)
*/
public int longitude;
/**
* What faction a town or village is aligned to. This determines production and consumption, mostly.
*/
public String faction;
/**
* What a specific village or town produces.
*/
public String[] production;
/**
* What a specific town consumes (villages don't consume)
*/
public String[] consumption;
/**
* How dangerous a specific town is with bandits
* A 1-10 scale, with 10 being the most dangerous.
* Any town with a danger over 8 can be raided and destroyed temporarily by bandits.
* Being raided successfully depends on the Strength of a town.
*/
public int danger;
/**
* How much a town takes in taxes.
*/
public float tax;
/**
* How easily a town is raided by bandits.
* If a bandit raid has a lower strength than the town, then the town wins.
*/
public int strength;
//
//
// METHODS
//
//
public int returnLatitude()
{
return latitude;
}
public int returnLongitude()
{
return longitude;
}
public String returnFaction()
{
return faction;
}
public String[] returnProduction()
{
return production;
}
public String[] returnConsumption()
{
return consumption;
}
public int returnDanger()
{
return danger;
}
public float returnTax()
{
return tax;
}
public int returnStrength()
{
return strength;
}
}
and townRey:
public class townRey extends settlement
{{
name = "Rey";
latitude = 5;
longitude = 5;
String faction = "Nord";
String[] production;
String[] consumption;
danger = 1;
tax = 0.05F;
strength = 6;
}}
EDIT:: Thanks for all the help! I fixed all issues now. Below is 'Settlement' and 'Start'.
public class Settlement
{
//
//
// VARIABLES
//
//
/**
* The town's unique name.
*/
public String name;
/**
* The settlement's location in latitude (N-S)
*/
public int latitude;
/**
* The settlement's location in longitude (E-W)
*/
public int longitude;
/**
* What faction a town or village is aligned to. This determines production and consumption, mostly.
*/
public String faction;
/**
* What a specific village or town produces.
*/
public String[] production;
/**
* What a specific town consumes (villages don't consume)
*/
public String[] consumption;
/**
* How dangerous a specific town is with bandits
* A 1-10 scale, with 10 being the most dangerous.
* Any town with a danger over 8 can be raided and destroyed temporarily by bandits.
* Being raided successfully depends on the Strength of a town.
*/
public int danger;
/**
* How much a town takes in taxes.
*/
public float tax;
/**
* How easily a town is raided by bandits.
* If a bandit raid has a lower strength than the town, then the town wins.
*/
public int strength;
//
//
// METHODS
//
//
public int returnLatitude()
{
return latitude;
}
public int returnLongitude()
{
return longitude;
}
public String returnFaction()
{
return faction;
}
public String[] returnProduction()
{
return production;
}
public String[] returnConsumption()
{
return consumption;
}
public int returnDanger()
{
return danger;
}
public float returnTax()
{
return tax;
}
public int returnStrength()
{
return strength;
}
}
and Start, where I create 'townRey' then access a bit of data in two different ways.
public class Start
{
public static void main(String[] args)
{
//Creates 'Rey'
Settlement townRey = new Settlement();
townRey.name = "Rey";
townRey.latitude = 5;
townRey.longitude = 5;
townRey.faction = "Nord";
townRey.danger = 1;
townRey.tax = 0.05F;
townRey.strength = 6;
//This calls the returnLongitude method from Settlement, and is the 'proper' way to do it.
System.out.println(townRey.returnLongitude());
//This also works.
System.out.println(townRey.longitude);
//Thanks for the help!
}
}
townRey shouldn't be extending settlement. You should be declaring it as an instance of settlement in some method, as follows:
townRey = new settlement();
townRey.name = "Rey";
...
townRey.strength = 6;
Or, better still, making a new constructor for settlement that takes the different fields as inputs.
Also, a style note: Generally, in Java, classes should begin with a capital letter, so Settlement rather than settlement might make a better name.
You should define a townRey object then use this object to call returnStrength
townRey mytownRey = new townRey();
System.out.println(townRey.returnStrength());
I expect you want townRey to be an instance of settlement, not a subclass. Unless you want to have multiple copies of townRey. Replace the line public class townRey extends settlement with settlement townRey = new settlement(), and add a semicolon after }}. Leave everything else the same.
public class mainclss()
{
public static void main(String arg[])
{
townRey= new settlement();
//you can do sth you like
}
}
create a new class to check.DO NOT start Java with Class!It is a little difficult.
Create a separate class with main() method. Inside this method, you should create an object of townRey, in order to access the method returnStrength(). You can't access it using the class name 'townRay' if you are doing so. So Add this class with the code below:
public class MainClass {
public static void main(String[] args) {
townRey tr = new townRey();
System.out.println( tr.returnStrength () );
}
}
This worked fine with me. So you can safely use it.
NOTE: You should learn by practice to start each word in your class name with a capital letter such as Settlement and TownRey. Good Luck!

Java Object Array Foreach Method Access

After developing in PHP for a long time I have decided to step into Java. Comfortable in OOP methodology and all that, I'm trying to start off at that point within java, but I'm getting hung up on passing out my arraylist object into a for statement to be printed back out using the Item class methods.
HelloInvetory.java
package helloInventory;
import java.util.Arrays;
public class HelloInventory {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Object InvetoryItems;
Inventory inv = new Inventory();
inv.createItemObj(101, "camera", "Used camera that I bought off of a homeless guy.", 500);
InvetoryItems = inv.getAllInventoryItems();
for(Object item : InvetoryItems){
System.out.println(item.getItemName());
}
System.out.println("Done");
}
}
Inventory.java
package helloInventory;
import java.util.*;
/**
* Tracks and maintains all items within the inventory
* #author levi
*
*/
public class Inventory {
List<Object> InventoryItems = new ArrayList<Object>();
/*
* create object from Items class
* and insert into Object[] array.
*/
public void createItemObj(int sku, String name, String descriptor, float price) {
Items item = new Items();
item.setSku(sku);
item.setItemName(name);
item.setItemDescription(descriptor);
item.setItemPrice(price);
this.setInventoryItems(item);
}
public Object getAllInventoryItems() {
//return InventoryItems;
return this.InventoryItems.toArray();
}
public void setInventoryItems(Object inventoryItems) {
//InventoryItems.add(inventoryItems);
this.InventoryItems.add(inventoryItems);
}
}
Items.java
package helloInventory;
/**
* Class object to hold each item details
* #author levi
*
*/
public class Items {
int sku;
String itemName;
String itemDescription;
float itemPrice;
public int getSku() {
return sku;
}
public void setSku(int sku) {
this.sku = sku;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemDescription() {
return itemDescription;
}
public void setItemDescription(String itemDescription) {
this.itemDescription = itemDescription;
}
public float getItemPrice() {
return itemPrice;
}
public void setItemPrice(float itemPrice) {
this.itemPrice = itemPrice;
}
}
Where I am stuck is within the HelloInventory.java
for(Object item : InvetoryItems){
System.out.println(item.getItemName());
}
IDE (Eclipse) gives me the error "Can only iterate over an array or an instance of java.lang.Iterable". Is there something extra I need, or I'm I going around this totally the wrong way in Java? Correct example would be helpful.
Best,
Levi
You have a very strange architecture here my friend. You shouldn't be using generic Objects everywhere, but the actual types. First thing:
public Object getAllInventoryItems() {
//return InventoryItems;
return this.InventoryItems.toArray();
}
Why not just return the List itself?
public List<Item> getAllInventoryItems() {
return this.InventoryItems;
}
Also change this:
List<Item> InventoryItems = new ArrayList<Item>();
and this:
public void setInventoryItems(Item inventoryItems) {
this.InventoryItems.add(inventoryItems);
}
Now iterating the List is smooth sailing:
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Item> InvetoryItems;
Inventory inv = new Inventory();
inv.createItemObj(101, "camera", "Used camera that I bought off of a homeless guy.", 500);
InvetoryItems = inv.getAllInventoryItems();
for(Item item : InvetoryItems){
System.out.println(item.getItemName());
}
System.out.println("Done");
}
Btw, I changed Items to Item out of habit. A class name should indicate a single entity so by convention it's singular.
Now don't take this the wrong way, but you may have got off on the wrong foot with Java, so I highly recommend this reading: http://www.mindview.net/Books/TIJ/ This worked for me when I was starting with Java, maybe others can suggest some good sources as well.
Ok, two things. One is that Tudor is absolutely right, it's best to use the classes you're expecting directly, not Objects, and stylistically his points are accurate too.
Two is that if you really have to use a list of object, you'll need to cast back from object to whatever type it is that you're expecting to receive.
List<Object> list = inv.getAllInventoryItems();
for (Object item : list){
System.out.println((Items) item).getItemName();
}
However, I wouldn't recommend doing this as it effectively takes what should be a compile-time error and makes it a RunTime error (if the class cannot be cast).

Categories