JUnit Testing assistance re logic needed - java

I am trying to formulate a JUnit test for the below code and I am hoping someone might be able to point me in the right direction as I am completely stumped!
public ArrayList<PathData> tileClicked(Coordinate tile){
ArrayList<PathData> pathData = new ArrayList<>();
Tile clickedTile = gameBoard.getTile(tile);
int totalNumPlayers = clickedTile.getNumberOfPlayers();
Player cur;
//GuiInstruction guiInstruction = new GuiInstruction();
//guiInstruction
if (clickedTile.hasPort()){
//deal with ports
for(int j = 0; j < totalNumPlayers; j++){
cur = clickedTile.getPlayerIndex(j);
if(cur.equals(currentPlayer)){
pathData = specialCalculateMove(currentPlayer, true);
}
}
} else if (clickedTile.hasPlayer()){
for(int i = 0; i < totalNumPlayers; i++){
cur = clickedTile.getPlayerIndex(i);
if(cur.equals(currentPlayer)){ //TODO: Is this if statement stupid?
pathData = normalCalculateMove(currentPlayer);
}
}
}else{
//TODO: Does this actually do anything?
}
return pathData;
}

A pretty broad question, thus you only get some broad hints (not going to write code for you!):
You have to understand A) what are parameters going into the method B) what are results resp. "observable" effects that your method can have
From there: you provide a single tile parameter; and depending on the actual state of that object, your method under test is using different paths
That translates to: you want to have at least one "test method" for each possible path through your method. That test method calls the method under test with an argument designed to take a certain path. You invoke the method under test; and then you check whether the result that is returned meets your expectations.

Related

How can I change code based on Method Argument?

public static void calculate(List<Person> data, String categoryType) {
for(int i = 0; i < categoryData.size(); i++) {
if(data.get(i).calculateCategoryOne() == firstPlace) {
...
}
}
}
If you see data.get(i).calculateCategoryOne(), the method call is for category one. The problem is that I need to copy-paste the entire code in a if-block for each category to just change this method call data.get(i).calculateCategoryTwo(), data.get(i).calculateCategoryThree(), ... data.get(i).calculateCategoryTen(),
While I can still make the logic work in this way, I feel it is redundant and not a good programming practice. Just to change one line of code, I would have to replicate the same code ten different times which will add nearly 500 lines of code.
So, my question is: Is there a way to dynamically change my method call based on the category type string argument.
I was thinking one possible way is to pass the method call in a string and convert it to a method call itself. For example, let's assume CategoryType string argument is "calculateCategoryOne()". So, data.get(i)."calculateCategoryOne()" would be recognized by the compiler as the method call itself. Is there a way to actually implement this?
I'm open to other ideas as well to reduce redundancy.
I would think using a functional interface would be appropriate here. You want different functionality depending on the categoryType, so passing in the function you want to use, rather than a String representation of it, would accomplish this.
#FunctionalInterface
public interface Calculate {
int calculate(Person data);
}
public static void calculate(List<Person> data, Calculate calculate) {
for(int i = 0; i < categoryData.size(); i++) {
if(calculate.calculate(data.get(i)) == firstPlace) {
...
}
}
}
and the call to the method would define what the calculation would be
calculate(list, p -> {
// calculation done here
});
or if this would happen frequently, you could predefine your categories once and pass those in:
Calculate categoryOne = p -> { ... };
Calculate categoryTwo = p -> { ... };
.
.
calculate(list, categoryOne);

Invoke Methods Dynamically on Java

At work, we have to generate a report for our client that changes its parameters several times during the week.
This report is generated from a single table on our database.
For example, imagine a table that has 100 columns and I have to generate a report with only 5 columns today, but tomorrow I have to generate with 95 of them.
With this in mind, I created a TO class with all the columns of the specified table and my query returns all columns (SELECT * FROM TABLE).
What I'm trying to create is a dynamic form to generate the report.
I first thought on create a simple frame with a list of the columns listed as check boxes and the user would select the columns that he wants (of course with a button to Select All and another to Deselect All).
As all of the columns have the same name as the attributes of the TO class, I developed the following code (I have Google this):
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
Is this the better way to do what I need to?
Thanks in advance.
Obs.: the getters of the TO class have the pattern "getAttribute_Name".
Note: This question is different from the one where the user is asking HOW to invoke some method given a certain name. I know how to do that. What I'm asking is if this is the better way to solve the problem I described.
My Java is a little more limited, but I believe that's about as good as you're going to get using reflection.
Class<?> c = Test.class;
for (String attribute : listOfAttributes) {
auxText += String.valueOf(c.getMethod("get" + attribute).invoke(this, null));
}
But since this sounds like it's from potentially untrusted data, I would advise using a HashMap in this case, with each method explicitly referenced. First of all, it explicitly states what methods can be dynamically called. Second, it's more type safe, and compile-time errors are way better than runtime errors. Third, it is likely faster, since it avoids reflection altogether. Something to the effect of this:
private static final HashMap<String, Supplier<Object>> methods = new HashMap<>();
// Initialize all the methods.
static {
methods.set("Foo", Test::getFoo);
methods.set("Bar", Test::getBar);
// etc.
}
private String invokeGetter(String name) {
if (methods.containsKey(name)) {
return String.valueOf(methods.get(name).get());
} else {
throw new NoSuchMethodException();
}
}
It might sound like a major DRY violation to do so, but the repetition at least makes sure you don't wind up with unrelated getters accidentally called.
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
You can do this somewhat more elegantly via Java Beans, the Introspector, and PropertyDescriptor, but it's a little more long-winded:
Map<String, Method> methods = new HashMap<>();
Class c = this.getClass(); // surely?
for (PropertyDescriptor pd : Introspector.getBeanInfo(c).getPropertyDescriptors())
{
map.put(pd.getName(), pd.getReadMethod();
}
//
for (int i = 0; i < listOfAttributes.length; i++)
{
Method m = methods.get(listOfAttributes[i]);
if (m == null)
continue;
auxText += String.valueOf(m.invoke(this, null));
}

Gridworld Fill Grid

Having trouble filling the grid. Everytime I do it I get a stackoverflow error. Here is my current code :
public void removeSelfFromGrid() {
Grid<Actor> grid = getGrid();
int rows = grid.getNumRows();
int cols = grid.getNumCols();
for (int i=0; i<rows; i++) {
for (int j=0; j<cols; j++) {
Location loc = new Location(i, j);
laugh = new CKiller();
laugh.putSelfInGrid(grid, loc);
}
}
}
and here is the constructor if needed
public CKiller()
{
Color c = null;
setColor(c);
getGrid();
getLocation();
location = new ArrayList<Location>();
location.add(getLocation());
setDirection(direction);
}
And here is the error (part of it, too big to post all. it's just those 2 statements repeated):
java.lang.StackOverflowError
at info.gridworld.actor.Actor.putSelfInGrid(Actor.java:123)
at CKiller.removeSelfFromGrid(CKiller.java:120)
It's saying this is the problem
laugh.putSelfInGrid(grid, loc);
Go through the following:
-Are you defining laugh prior to the removeSelfFromGrid() method call? It doesn't have a type specified before it.
-Should the variable location not be an ArrayList? It might be a Location object.
-Is the int direction defined already?
-Why are you calling getGrid() and getLocation()? They aren't doing anything beneficial.
-Does CKiller inherit the putSelfInGrid() method from the Actor class?
Please include the full code of the CKiller class as well as the main class that contains removeSelfFromGrid().
I think your problem is that you overrode the removeSelfFromGrid() method. You should have created a new method, such as fillGrid().
When an actor calls putSelfInGrid(), if there is currently another actor in that Location it calls removeSelfFromGrid(), which you overrode to fill every Location on the Grid with an actor. If there are any other actors on the grid they will then call removeSelfFromGrid(), which leads to again filling the grid, etc.
Just fix the code in removeSelfFromGrid(), put it in a new method and restore the previous code, and you should be good.

How to adding two method returns together

Ok, So I have a method
public static int getTotalLegCountDog (ArrayList<Dog> dogList)
{
int temp = 0;
for (int i = 0; i < dogList.size(); i++)
{
temp = dogList.get(i).getNumLegs();
totalLegsDogs += temp;
}
return totalLegsDogs;
}
It adds up the total legs of dogs and returns them as totalLegsDogs and there is another that totals the legs for cats.
Now I'd like a method that would take both the returned totalLegsDogs and returned totalLegsCats and add them together. My try is below (It returns 0), any help would be great!
public int getTotalLegCount ()
{
totalLegs = totalLegsDogs + totalLegsCats;
return totalLegs;
}
Was not calling the Method correctly. The math in the Problem was solid. The problem was the Method output call.
As far as I can tell, there's nothing wrong with the methods themselves - likely you're calling getTotalLegCount before actually counting the legs.
Fix 1 (preferred): Have getTotalLegCount call the methods.
public int getTotalLegCount (ArrayList<Dog> dogList, ArrayList<Cat> catList) {
totalLegs = getTotalLegCountDog(dogList) + getTotalLegCountCat;
return totalLegs;
}
Fix 2: Make it very clear that the leg-counting methods are to be called first. This is the inferior solution, as it requires more effort on the future programmer's part (and that might be future-you!).
I don't think you've shown us enough of your code to do any troubleshooting. It looks like you must have a global static count for dog legs and cat legs? I can't figure out your use case, but any rate, you need to make sure both your counting methods are called before you do anything with the member variables or else they will not be initialized. Example:
DogCatCounter.getTotalLegDogCount(...);
DogCatCounter.getTotalLegCatCount(...);
new DogCatCounter().getTotalLegCount();
The result from that third line should be correct as long as no other instances of DogCatCounter have modified your static variables. In other words, if you have multiple instances of DogCatCounter, any calls to your counting methods are going to modify your global static members.

I fail junit tests because of return type (I think)

So I have a class full of junit tests and a class full of methods that perform binary operations. The tests are checking to see if I have the right values at certain points.
I am failing a lot of tests because of what I believe to be is the return type. For example I get the message
junit.framework.ComparisonFailure: null expected:<[000]> but was <[BinaryNumber#4896b555]>
If I'm understanding this it's saying that it was looking for an array containing 000 but it got a BinaryNumber (which is the required return type). To help clarify here is one of the methods.
public BinaryADT and(BinaryADT y) {
int[] homeArr = pad(((BinaryNumber) y).getNumber());
int[] awayArr = ((BinaryNumber) y).pad(getNumber());
int[] solution = new int[awayArr.length];
int i = 0;
String empty = "";
while(i < solution.length){
solution[i] = homeArr[i] & awayArr[i];
i++;
}
for(int indexF = 0; indexF < solution.length; indexF++){
empty = empty + solution[indexF];
}
System.out.println(empty);
return new BinaryNumber(empty);
}
Am I understanding this right? If not could someone please explain? I'd also like to point out that this is for my homework but I'm not asking for answers/someone to do it for me. Just a point in the right direction at most.
I will gladly clarify more if it is needed (I didn't want to bog everything down).
Also this is my first post on here. I tried to keep to the formatting suggestions but I apologize if anything is sub-par.
As suggested here is the test method
public void testAnd1()
{
BinaryADT x = new BinaryNumber("111");
BinaryADT y = new BinaryNumber("000");
BinaryADT z = x.and(y);
assertNotSame(x,z);
assertNotSame(y,z);
assertEquals("000",z.toString());
}
Whenever you see the output of "toString()" like ClassName#SomeNumber, then you can be sure that toString() method is not implemented for that class (unless toString() method implementation itself is not like this).
In your case, expected value is [000], but you are getting [BinaryNumber#4896b555].
Try to implement toString() method in BinaryNumber class and return the value from this method as per assertEquals() expects. This should solve the problem.
Can you show me your test code?
1.Your expected type is different from the actual type.
2.BinaryADT class didn't overide toString method.

Categories

Resources