I'm kind of mediocre at Java at the moment, and new to JUnit, but I can't find the answer to this question elsewhere.
I want to use a constant variable defined within the class I am testing, within the Junit test case itself, but since it's a static final, it's not available.
The class I'm testing is as follows:
public class MyClass {
private static final int HSIZE = 7;
private static final int NUM_LOCS = 3;
.
.
.
void generateRandomLocations() {
Random rand = new Random();
String[] hPos = new String[NUM_LOCS];
for (int i=0; i<NUM_LOCS; i++) {
hPos[i] = Integer.toString(rand.nextInt(HSIZE));
}
setLocations(hPos);
}
}
Simple enough, and it seems to work OK, but I'd like to add a test case in JUnit - something like the following:
#Test
void testGenerateRandomLocations() {
MyClass mc = new MyClass();
mc.generateRandomLocations();
String[] check = mc.getLocations();
assertEquals(sadc.NUM_LOCS, check.length);
}
(The getter is defined, I just haven't included it here for brevity)
However (of course) sadc.NUM_LOCS is not available because it's only visible in MyClass.
How can I access this from a JUnit (5) test case?
I've used #VisibleForTesting annotation which annotates why normally private variables and methods are protected instead. They're not fully visible, but can be accessed for testing purposes. I've used this with what were private static final variables.
The example I've seen/worked with used a file called VisibleForTesting.java that contained:
package your.pkg.here;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Indicates that the class, method or field has greater
* visibility than otherwise needed to enhance testability.
*/
#Retention(SOURCE)
public #interface VisibleForTesting {
}
Then within the class you want to test you set the method or variable to protected, and use the #VisibleForTesting annotation:
public class MyClass {
private static final int HSIZE = 7;
#VisibleForTesting
protected static final int NUM_LOCS = 3;
void generateRandomLocations() {
Random rand = new Random();
String[] hPos = new String[NUM_LOCS];
for (int i=0; i<NUM_LOCS; i++) {
hPos[i] = Integer.toString(rand.nextInt(HSIZE));
}
setLocations(hPos);
}
}
This allows the tests to see it, but the variable is not available to the public, and there is an explanation for why it's not private. #VisibleForTesting can also be found in Google's Guava library, so you could include that instead of adding VisibleForTesting.java, but I haven't used that.
Have you try using Powermockito. Whitebox has getInternalState.
see if it helps
https://github.com/powermock/powermock/wiki/Bypass-Encapsulation
Simple answer
Make variable NUM_LOCS public. However, this is a poor design.
Better answer
Instead of static variable, pass NUM_LOCS through constructor:
public class MyClass {
private final int numLocs;
public MyClass(int numLocs) {
this.numLocs = numLocs;
}
//default ctor with default numLocs value
public MyClass() {
this.numLocs = 3;
}
//methods
}
Now, your test looks like this:
#Test
void testGenerateRandomLocations() {
int expectedNumLocs = 7;
MyClass mc = new MyClass(7);
mc.generateRandomLocations();
String[] check = mc.getLocations();
assertEquals(expectedNumLocs, check.length);
}
and you can make a test to check default value is 3, too:
#Test
void testGenerateRandomLocations() {
int expectedNumLocs = 3;
MyClass mc = new MyClass(); //no args
mc.generateRandomLocations();
String[] check = mc.getLocations();
assertEquals(expectedNumLocs, check.length);
}
Related
I was writing this piece of code to understand reflection and encountered one scenario where I couldn't really figure out the reason for the codes' behavior. Hopefully I receive some guidance from the community.
Following is my test model class & here, for every instantiation, I want to know the exact number of instances created during runtime (using reflection)
public final class Model {
private static final Model instance = new Model("Testing");
private static int count = 0;
private String name;
private Model(String name) {
this.name = name;
++count;
}
public static Model getInstance() {
return instance;
}
public static int getInstanceCount() {
return count;
}
public String getName() {
return name;
}
public void doSomething() {
try {
System.out.println("Shh.... I am trying to do something");
Thread.sleep(1000);
System.out.println("Ok! Done.");
return;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Oops! I failed in doing your job...");
}
}
The driver code for this scenario is as follows,
public class ReflectionTest {
public static void main(String[] args) throws Exception {
Model.getInstance().doSomething();
System.out.println(Model.getInstanceCount());
Constructor<?>[] constructor = Model.class.getDeclaredConstructors();
for (Constructor<?> aConstructor : constructor) {
aConstructor.setAccessible(true);
Model m = (Model) aConstructor.newInstance("Testing through Reflection");
System.out.println(m.getName());
m.doSomething();
System.out.println(m.getInstanceCount());
//System.out.println(Model.getInstanceCount());
}
}
}
The output for this above piece of code came out to be as follows,
Shh.... I am trying to do something
Ok! Done.
0
Testing through Reflection
Shh.... I am trying to do something
Ok! Done.
1
As you can see, the instance count came out to be 1. I expected it to be as 2.
However, I changed the test model class's constructor as shown below. The datatype of count is now changed to Integer, instead of previously set 'int'.
private Model(String name) {
this.name = name;
if (count == null)
count = 0;
++count;
}
Surprisingly, I get the correct value for the instance count.
Shh.... I am trying to do something
Ok! Done.
1
Testing through Reflection
Shh.... I am trying to do something
Ok! Done.
2
This might be a silly question, but I am not able to ponder on what really happened behind the scenes. I need some guidance from the community on this.
Thanks in advance.
This has nothing to do with reflection.
private static final Model instance = new Model("Testing");
private static int count = 0;
The initializers are executed in order. So:
private static final Model instance = new Model("Testing");
Executing the constructor causes count to be incremented from 0 to 1, but then:
private static int count = 0;
Sets count back to zero.
Reverse the order of the declarations.
private static int count = 0;
private static final Model instance = new Model("Testing");
Or omit the initializer on count (its default value is zero anyway).
private static final Model instance = new Model("Testing");
private static int count;
I have a little problem in a simple class.
import java.util.Random;
public class fileTest {
private static Random rand = new Random();;
private int randOne = rand.nextInt(10);
private String strOne = String.format("%02d", this.randOne);
public int getRandOne() {
return randOne;
}
public void setRandOne(int randOne) {
this.randOne = randOne +1;
}
public String getStrOne() {
return strOne;
}
}
My "launcher"
public class launch {
public static void main(String[] args) {
fileTest fileA = new fileTest();
System.out.println(fileA.getStrOne());
//FunctionDoMyStuff...
fileA.setRandOne(fileA.getRandOne());
System.out.println(fileA.getRandOne());
//RandOne is increment
System.out.println(fileA.getStrOne());
//StrOne is not
}
}
My idea is to create a random number and transform it into a string.
After finishing my stuff, I need to increment my string.
But the result after the setter is the same as in the beginning. I think I don't understand everything about a getter/setter.
Can anyone help me to understand my mistake?
This happens once at the time that your instance is created:
private String strOne = String.format("%02d", this.randOne);
It isn't automatically run again after you change randOne. The solution is to remove the strOne field altogether and construct the String inside the getter:
public String getStrOne() {
return String.format("%02d", this.randOne);
}
You don't need to store a dynamically derived value.
The behaviour of your method setRandOne doesn't match what people might reasonably expect a set method to do. A method that does what yours does could be described as setRandOneToOneHigherThan(int value). Or you could call it incrementRandOne() but then the body needs to do this.randOne = this.randOne + 1; (or this.randOne++;). Or you could make it a normal setter and do the incrementing while you call the method: fileA.setRandOne(fileA.getRandOne() + 1);.
I'm having problems with two void methods. In encouragedVenturesScoring I've followed this answer mocking an arraylist that will be looped in a for loop and haven't mocked the list, but passed a real list and added mocked objects.
Mockito gives me an InvalidUseOfMatchersException on this line
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
There are lots of questions on SO on this exception , and I think it's because of anyInt(). Anyway I changed it to
verify(effectList.get(0)).execute(playerHandler);
And now it's saying Wanted but not invoked effect.execute(playerHandler)
Actually there were zero interactions with this mock
Is it because I put doNothing ?
doNothing().when(effect).execute(playerHandler);
In my second method militaryStrengthScoring() method is there a way to skip the first chunk of code and just test the if..else condition? What would be the best approach to test this method?
Thank you for your time.
This is the class to be tested
public class EndGameScoringBaseController implements EndGameScoringHandler {
private static final int[] TERRITORIES_REWARD = {0,0,1,4,10,20};
private static final int[] CHARACTERS_REWARD = {1,3,6,10,15,21};
private static final int RESOURCES_RATE = 5;
private static final int FIRST_MILITARY_REWARD = 5;
private static final int SECOND_MILITARY_REWARD = 2;
private PlayerHandler player;
public EndGameScoringBaseController(PlayerHandler player) {
super();
this.player = player;
}
#Override
public void encouragedVenturesScoring() {
for (DevelopmentCard card : player.getPlayer().getPersonalBoard().getVentures()) {
for (Effect e : card.getPermanentEffects())
e.execute(player);
}
}
#Override
public void militaryStrengthScoring(GameController game) {
Set<Integer> points = new HashSet<>();
int myPoints = this.player.getPointsHandler().getMilitaryPoints();
for (PlayerHandler p: game.getPlayers()) {
points.add(p.getPointsHandler().getMilitaryPoints());
}
int[] rank = new int[points.size()];
int j = 0;
for (Integer i : points) {
rank[j] = i;
j++;
}
Arrays.sort(rank);
if (rank[rank.length-1] == myPoints) {
player.getPointsHandler().winMilitaryPoints(FIRST_MILITARY_REWARD);
}
else if (rank[rank.length-2] == myPoints) {
player.getPointsHandler().winVictoryPoints(SECOND_MILITARY_REWARD);
}
}
Tested method for encouragedVenturesScoring
#Test
public void encouragedVenturesScoringTest() {
//given
List<DevelopmentCard> ventureList;
ventureList = Arrays.asList(developmentCard, developmentCard);
when(playerHandler.getPlayer().getPersonalBoard().getVentures()).thenReturn(ventureList);
List<Effect> effectList;
effectList = Arrays.asList(effect, effect);
when(developmentCard.getPermanentEffects()).thenReturn(effectList);
doNothing().when(effect).execute(playerHandler);
//when
endgameController.encouragedVenturesScoring();
//then
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
}
Incomplete tested method for militaryStrengthScoring
#Test
public void militaryStrengthScoringTest() {
//given
when(playerHandler.getPointsHandler().getMilitaryPoints()).thenReturn(4);
doNothing().when(playerHandler.getPointsHandler()).winMilitaryPoints(FIRST_MILITARY_REWARD);
//when
endgameController.militaryStrengthScoring(gameController);
//then
/../
}
You're right that this is the problem:
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
Mockito only allows for calls like any() and anyInt() to stand in for parameters to the mock themselves, due to the internal implementation of matchers.
/* OK */ when(yourMock.yourMethod(anyInt())).thenReturn(42);
/* BAD */ when(yourList.get(anyInt()).yourMethod(0)).thenReturn(42);
/* OK */ verify(yourMock).yourMethod(anyInt());
/* BAD */ verify(yourList.get(anyInt())).yourMethod(0);
The failure with get(0) is likely an actual failure, and may be related to the fact that your encouragedVenturesScoringTest is actually not calling encouragedVenturesScoring, it's calling influencedCharactersScoring. If this continues to give you trouble after fixing that error, in ways related to Mockito, please edit your question.
You can only verify mock objects created by Mockito.
But effectList is a "real" list. Therefore Mockito knows nothing about that object. Thus any attempt to verify that list must fail.
If you want to verify that object - then you have to mock it!
Of course, this means that you have specify all calls that will go to the mocked list.
I'm new to Java and we have to make this little project. So i have 3+ classes.
MY code is in pastebin
http://pastebin.com/GEq9DLiP
etc. etc.
Problem is, that in 3rd class it sais
"kangelane cannot be resolved"
but kangelane is already "defined" in Main.java and they are in same package.
Oh and Eclipse also wants to add "open bracet" after
int sook = 4; or
int dam;
and also "clode bracket" to the end
even though all open brackets are closed and vice versa
I have Getters and Setters in "Voitleja.java", so that works.
It also worked, when i only had 2 classes not 3 (Voitlus was in Main)
The problem is that main is a static class, if you want to use a variable in both main and in an oter class, you have to defined it as a static variable, for your example you should do :
public class Main {
static Voitleja kangelane;
public static void main(String[] args) {
String nimi = JOptionPane.showInputDialog("Sisestage võitleja nimi");
kangelane = new Voitleja(nimi, 55, 12);
}
}
Then in your other class (assuming the import are correct)
public class Voitlus{
Random generator = new Random();
int dam;
int sook = 4;
while (true) {
Main.kangelane.setElud(kangelane.getElud() + 7);
}
}
public static void main(String[] args) {
String nimi = JOptionPane.showInputDialog("Sisestage võitleja nimi");
Voitleja kangelane = new Voitleja(nimi, 55, 12);
}
(later)
while (true) {
kangelane.setElud(kangelane.getElud() + 7);
}
The variables are in a different scope. You have to declare kangelane right after your public class declaration so both methods can "see" it.
When I run this code i get 2 numbers (which is good) but the numbers generated are the same (which is bad) and I dont want the numbers to be the same. I've done this as an experiment for a rpg I was going to make so I thought it would be beter if each weapon had a different class.
The main class:
package battlesimMK2;
public class Main {
public static void main(String Arg[]) {
String WeponEquiped = "BasicAxe";
System.out.print(BasicAxe.Str);
System.out.print(BasicAxe.Str);
}
}
The basic axe class:
package battlesimMK2;
import java.util.Random;
public class BasicAxe {
static Random rnd = new Random();
static int Str = rnd.nextInt(4)+5;
}
This line:
static int Str = rnd.nextInt(4)+5;
declares a static variable and initializes it once. If you want the code to run each to you access Str, you should make it a method:
public static int getStrength() {
return rnd.nextInt(4)+5;
}
Then call it with this code in Main.main:
System.out.print(BasicAxe.getStrength());
System.out.print(BasicAxe.getStrength());
An alternative which would probably be more object-oriented would be to make the strength an instance field, so that each axe created had a possibly-different (but persistent) strength:
public class BasicAxe {
private static final Random rnd = new Random();
private final int strength;
public BasicAxe() {
strength = rnd.nextInt(4)+5;
}
public int getStrength() {
return strength;
}
}
Then in Main.main:
BasicAxe axe1 = new BasicAxe();
BasicAxe axe2 = new BasicAxe();
System.out.println(axe1.getStrength());
System.out.println(axe2.getStrength());
System.out.println(axe1.getStrength());
Here, the first and third lines of output will be the same - but the second will (probably) be different.
You're generating a single random number and printing it twice. Try something like this instead:
package battlesimMK2;
public class Main {
public static void main(String Arg[]) {
String WeponEquiped = "BasicAxe";
System.out.print(BasicAxe.Str());
System.out.print(BasicAxe.Str());
}
}
package battlesimMK2;
import java.util.Random;
public class BasicAxe {
static Random rnd = new Random();
static int Str() { return rnd.nextInt(4)+5; }
}
This because this line
static int Str = rnd.nextInt(4)+5;
runs just one time in whole the lifecycle of your application. It's static value, you should use static method instead.
Because you define the Str variable as static, only a single copy of that variable is shared between all your BasicAxe classes.
The way to get a different answer each time you ask for the int value is, to use the example posted by the previous poster,
String WeponEquiped = "BasicAxe";
System.out.print(BasicAxe.getStrength());
System.out.print(BasicAxe.getStrength());
But, if you want to create an actual instance of the class BasicAxe, which keeps it's value so that each time you ask for the strength you get the same value, you'll need something different.