I'm trying to test implementations of a Collections interface using JUnit4 Parameterized tests. My test class has two tests:
#RunWith(Parameterized.class)
public class CollectionsTest {
private Collection<String> col;
private Collection<String> other;
public CollectionsTest(Collection<String> c, Collection<String> other) {
this.col = c;
this.other = other;
}
#Parameterized.Parameters
public static java.util.Collection<Object[]> tokenStreams() {
return (java.util.Collection<Object[]>) Arrays.asList(new Object[][] {
{ new DSLinkedList<String>(), new DSLinkedList<String>() } });
}
#Test
public final void isEmpty() {
assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty());
col.add("Stringthing");
assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
}
#Test
public final void size() {
assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
col.add("String");
assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());
}
}
The second test (size()) always fails: at the time of the first assertion, col contains a single element stringThing, because I inserted an element in the isEmpty() test.
How do I clean the parameterized objects between tests?
If I wasn't using a parameterized test, I'd use #Before with a setup() method: should I be using reflection and a setup method here to recreate the col and other objects? (I haven't done this because I don't know which Collection implementation each test is running beforehand: if I have to manually write code using reflection to determine this, what's the point of Parameterized tests?)
My understanding is that the Parameterized tests call the constructor before each test, which should 'reset' my objects cleanly: why is this not the case?
Parameterized creates a new CollectionsTest object before each tests and calls the constructor, but it passes the same DSLinkedList objects each time, tokenStreams() is called only once for whole testcase. You should clean the lists in the constructor yourself.
In Java 8 this can be done fairly cleanly using lambda expressions and the utility class java.util.function.Supplier. Instead of providing an instance of the parameter type, you provide a lambda which supplies a new instance each time it is evaluated. JUnit passes the lambda to the constructor for each test case, where a new instance is created with a call to get().
#RunWith(Parameterized.class)
public class CollectionsTest {
private Collection<String> col;
private Collection<String> other;
public CollectionsTest(Supplier<Collection<String>> c, Supplier<Collection<String>> other) {
this.col = c.get();
this.other = other.get();
}
#Parameterized.Parameters
public static java.util.Collection<Object[]> tokenStreams() {
Supplier<Collection<String>> c1 = () -> new DSLinkedList<String>();
Supplier<Collection<String>> c2 = () -> new DSLinkedList<String>();
return Arrays.asList(new Object[][] { { c1, c2 } });
}
#Test
public final void isEmpty() {
assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty());
col.add("Stringthing");
assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
}
#Test
public final void size() {
assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
col.add("String");
assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());
}
This is a late response. But I had the same dilemma and I solved it like this:
#RunWith(Parameterized.class)
public class CollectionsTest {
private Collection<String> col;
private Collection<String> other;
private Class<Collection> source1;
private Class<Collection> source2;
public CollectionsTest(Class<Collection> first, Class<Collection> second) {
this.source1 = first;
this.source2 = second;
}
#Parameters
public static Collection<Object[]> instancesToTest() {
return Arrays.asList(new Object[][] {
{ DSLinkedList.class, DSLinkedList.class },
{ OtherCollection.class, MyCollection.class }
});
}
#Before
public void setUp() throws Exception {
this.col = source1.newInstance();
this.other = source2.newInstance();
}
. . .
This approach works as long as your classes have a default constructor (no arguments).
The #Before setup() method gets called before each test and creates a new instance for your objects.
To use non-default constructors yo can use getConstructor() to choose which constructor you want:
this.col = source1.getConstructor(String.class).newInstance("Hello object");
You can create new objects within your tests too, using the same technique (e.g. Collection<String> c1 = source1.newInstance()), those tests have to throw an Exception (you will get a compile time error if they don't)
Well, you are changing the member variable value though. So, are you expecting the constructor to be called before each test? Also, as per the documentation of Parameterized. Your Test class instance would be provided with the data values in the #Parameters method. It isnt every test it is the instance of the class.
Parameterized
Related
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 have a code which calculates something, caches is, and if already calculated, then reads from the cache; similar to this:
public class LengthWithCache {
private java.util.Map<String, Integer> lengthPlusOneCache = new java.util.HashMap<String, Integer>();
public int getLenghtPlusOne(String string) {
Integer cachedStringLenghtPlusOne = lengthPlusOneCache.get(string);
if (cachedStringLenghtPlusOne != null) {
return cachedStringLenghtPlusOne;
}
int stringLenghtPlusOne = determineLengthPlusOne(string);
lengthPlusOneCache.put(string, new Integer(stringLenghtPlusOne));
return stringLenghtPlusOne;
}
protected int determineLengthPlusOne(String string) {
return string.length() + 1;
}
}
I want to test if function determineLengthPlusOne has been called adequate number of times, like this:
public class LengthWithCacheTest {
#Test
public void testGetLenghtPlusOne() {
LengthWithCache lengthWithCache = new LengthWithCache();
assertEquals(6, lengthWithCache.getLenghtPlusOne("apple"));
// here check that determineLengthPlusOne has been called once
assertEquals(6, lengthWithCache.getLenghtPlusOne("apple"));
// here check that determineLengthPlusOne has not been called
}
}
Mocking class LengthWithCache does not seem a good option, as I want to test their functions. (According to my understanding we mock the classes used by the tested class, and not the tested class itself.) Which is the most elegant solution for this?
My first idea was to create another class LengthPlusOneDeterminer containing function determineLengthPlusOne, add pass it to function getLenghtPlusOne as parameter, and mock LengthPlusOneDeterminer in case of unit testing, but that seems a bit strange, as it has unnecessary impact on the working code (the real clients of class LengthWithCache).
Basically I am using Mockito, but whatever mock framework (or other solution) is welcome! Thank you!
Most elegant way would be to create a separate class that does the caching and decorate with it the current class (after removal of the caching), this way you can safely unit test the caching itself without interfering with functionalities of the base class.
public class Length {
public int getLenghtPlusOne(String string) {
int stringLenghtPlusOne = determineLengthPlusOne(string);
lengthPlusOneCache.put(string, new Integer(stringLenghtPlusOne));
return stringLenghtPlusOne;
}
protected int determineLengthPlusOne(String string) {
return string.length() + 1;
}
}
public class CachedLength extends Length {
private java.util.Map<String, Integer> lengthPlusOneCache = new java.util.HashMap<String, Integer>();
public CachedLength(Length length) {
this.length = length;
}
public int getLenghtPlusOne(String string) {
Integer cachedStringLenghtPlusOne = lengthPlusOneCache.get(string);
if (cachedStringLenghtPlusOne != null) {
return cachedStringLenghtPlusOne;
}
return length.getLenghtPlusOne(string);
}
}
Then you can easily test the caching my injecting a mocked Length:
Length length = Mockito.mock(Length.class);
CachedLength cached = new CachedLength(length);
....
Mockito.verify(length, Mockito.times(5)).getLenghtPlusOne(Mockito.anyInt());
You don't need mock to address your need.
To test the internal behavior (is getLenghtPlusOne() was called or not called), you would need to have a method to access to the cache in LengthWithCache.
But at level of your design, we imagine that you don't want to open the cache in a public method. Which is normal.
Multiple solutions exist to do a test on the cache behavior despite this constraint.
I will present my way of doing. Maybe, there is better.
But I think that in most of cases, you will be forced to use some tricks or to complexify your design to do your unit test.
It relies on augmenting your class to test by extending it in order to add the needed information and behavior for your test.
And it's this subclass you will use in your unit test.
The most important point in this class extension is not to break or modify the behavior of the object to test.
It must add new information and add new behavior and not modify information and behavior of the original class otherwise the test loses its value since it doesn't test any longer the behavior in the original class.
The key points :
- having a private field lengthPlusOneWasCalledForCurrentCallwhich registers for the current call if the method lengthPlusOneWasCalledwas called
- having a public method to know the value of lengthPlusOneWasCalledForCurrentCall for the string used as parameter. It enable the assertion.
- having a public method to clean the state of lengthPlusOneWasCalledForCurrentCall. It enable to keep a clean state after the assertion.
package cache;
import java.util.HashSet;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
public class LengthWithCacheTest {
private class LengthWithCacheAugmentedForTest extends LengthWithCache {
private Set<String> lengthPlusOneWasCalledForCurrentCall = new HashSet<>();
#Override
protected int determineLengthPlusOne(String string) {
// start : info for testing
this.lengthPlusOneWasCalledForCurrentCall.add(string);
// end : info for testing
return super.determineLengthPlusOne(string);
}
// method for assertion
public boolean isLengthPlusOneCalled(String string) {
return lengthPlusOneWasCalledForCurrentCall.contains(string);
}
// method added for clean the state of current calls
public void cleanCurrentCalls() {
lengthPlusOneWasCalledForCurrentCall.clear();
}
}
#Test
public void testGetLenghtPlusOne() {
LengthWithCacheAugmentedForTest lengthWithCache = new LengthWithCacheAugmentedForTest();
final String string = "apple";
// here check that determineLengthPlusOne has been called once
Assert.assertEquals(6, lengthWithCache.getLenghtPlusOne(string));
Assert.assertTrue(lengthWithCache.isLengthPlusOneCalled(string));
// clean call registered
lengthWithCache.cleanCurrentCalls();
// here check that determineLengthPlusOne has not been called
Assert.assertEquals(6, lengthWithCache.getLenghtPlusOne(string));
Assert.assertFalse(lengthWithCache.isLengthPlusOneCalled(string));
}
}
Edit 28-07-16 to show why more code is needed to handle more scenarios
Suppose, i will improve the test by asserting that there is no side effects : adding an element in the cache for a key has not effect on how the cache is handled for other keys.
This test fails because it doesn't rely on the string key. So, it always increments.
#Test
public void verifyInvocationCountsWithDifferentElementsAdded() {
final AtomicInteger plusOneInvkCounter = new AtomicInteger();
LengthWithCache lengthWithCache = new LengthWithCache() {
#Override
protected int determineLengthPlusOne(String string) {
plusOneInvkCounter.incrementAndGet();
return super.determineLengthPlusOne(string);
}
};
Assert.assertEquals(0, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne("apple");
Assert.assertEquals(1, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne("pie");
Assert.assertEquals(1, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne("eggs");
Assert.assertEquals(1, plusOneInvkCounter.get());
}
My version is longer because it provides more features and so, it can handle a broader range of unit testing scenarios .
Edit 28-07-16 to point the Integer caching
No direct relation with the original question but little wink :)
Your getLenghtPlusOne(String string) should use Integer.valueOf(int) instead of new Integer(int)
Integer.valueOf(int) uses in internal a cache
It feels like using mocks is overthinking it. The LengthWithCache can be overridden as an anonymous-inner class within the context of a test to get the invocation count. This requires no restructuring of the existing class being tested.
public class LengthWithCacheTest {
#Test
public void verifyLengthEval() {
LengthWithCache lengthWithCache = new LengthWithCache();
assertEquals(6, lengthWithCache.getLenghtPlusOne("apple"));
}
#Test
public void verifyInvocationCounts() {
final AtomicInteger plusOneInvkCounter = new AtomicInteger();
LengthWithCache lengthWithCache = new LengthWithCache() {
#Override
protected int determineLengthPlusOne(String string) {
plusOneInvkCounter.incrementAndGet();
return super.determineLengthPlusOne(string);
}
};
lengthWithCache.getLenghtPlusOne("apple");
assertEquals(1, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne("apple");
lengthWithCache.getLenghtPlusOne("apple");
lengthWithCache.getLenghtPlusOne("apple");
lengthWithCache.getLenghtPlusOne("apple");
lengthWithCache.getLenghtPlusOne("apple");
lengthWithCache.getLenghtPlusOne("apple");
assertEquals(1, plusOneInvkCounter.get());
}
}
It's worth noting the separation between the two tests. One verifies
that the length eval is right, the other verifies the invocation
count.
If a wider data set for validation is required, then you can turn the Test above into a Parameterized test and provide multiple data sets and expectations. In the sample below I've added a data set of 50 strings (lengths 1-50), an empty string, and a null value.
Null fails
#RunWith(Parameterized.class)
public class LengthWithCacheTest {
#Parameters(name="{0}")
public static Collection<Object[]> buildTests() {
Collection<Object[]> paramRefs = new ArrayList<Object[]>();
paramRefs.add(new Object[]{null, 0});
paramRefs.add(new Object[]{"", 1});
for (int counter = 1 ; counter < 50; counter++) {
String data = "";
for (int index = 0 ; index < counter ; index++){
data += "a";
}
paramRefs.add(new Object[]{data, counter+1});
}
return paramRefs;
}
private String stringToTest;
private int expectedLength;
public LengthWithCacheTest(String string, int length) {
this.stringToTest = string;
this.expectedLength = length;
}
#Test
public void verifyLengthEval() {
LengthWithCache lengthWithCache = new LengthWithCache();
assertEquals(expectedLength, lengthWithCache.getLenghtPlusOne(stringToTest));
}
#Test
public void verifyInvocationCounts() {
final AtomicInteger plusOneInvkCounter = new AtomicInteger();
LengthWithCache lengthWithCache = new LengthWithCache() {
#Override
protected int determineLengthPlusOne(String string) {
plusOneInvkCounter.incrementAndGet();
return super.determineLengthPlusOne(string);
}
};
assertEquals(0, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne(stringToTest);
assertEquals(1, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne(stringToTest);
assertEquals(1, plusOneInvkCounter.get());
lengthWithCache.getLenghtPlusOne(stringToTest);
assertEquals(1, plusOneInvkCounter.get());
}
}
Parameterized testing is one of the best ways to vary your data set through a test, but it adds complexity to the test and can be difficult to maintain. It's useful to know about, but not always the right tool for the job.
As this was an interesting question, I decided to write the tests. In two different ways, one with mocking and the other without. (Personally, I prefer the version without mocking.) In either case, the original class is tested, with no modifications:
package example;
import mockit.*;
import org.junit.*;
import static org.junit.Assert.*;
public class LengthWithCacheMockedTest {
#Tested(availableDuringSetup = true) #Mocked LengthWithCache lengthWithCache;
#Before
public void recordComputedLengthPlusOneWhileFixingTheNumberOfAllowedInvocations() {
new Expectations() {{
lengthWithCache.determineLengthPlusOne(anyString); result = 6; times = 1;
}};
}
#Test
public void getLenghtPlusOneNotFromCacheWhenCalledTheFirstTime() {
int length = lengthWithCache.getLenghtPlusOne("apple");
assertEquals(6, length);
}
#Test
public void getLenghtPlusOneFromCacheWhenCalledAfterFirstTime() {
int length1 = lengthWithCache.getLenghtPlusOne("apple");
int length2 = lengthWithCache.getLenghtPlusOne("apple");
assertEquals(6, length1);
assertEquals(length1, length2);
}
}
package example;
import mockit.*;
import org.junit.*;
import static org.junit.Assert.*;
public class LengthWithCacheNotMockedTest {
#Tested LengthWithCache lengthWithCache;
#Test
public void getLenghtPlusOneNotFromCacheWhenCalledTheFirstTime() {
long t0 = System.currentTimeMillis(); // millisecond precision is enough here
int length = lengthWithCache.getLenghtPlusOne("apple");
long dt = System.currentTimeMillis() - t0;
assertEquals(6, length);
assertTrue(dt >= 100); // assume at least 100 millis to compute the expensive value
}
#Test
public void getLenghtPlusOneFromCacheWhenCalledAfterFirstTime() {
// First time: takes some time to compute.
int length1 = lengthWithCache.getLenghtPlusOne("apple");
// Second time: gets from cache, takes no time.
long t0 = System.nanoTime(); // max precision here
int length2 = lengthWithCache.getLenghtPlusOne("apple");
long dt = System.nanoTime() - t0;
assertEquals(6, length1);
assertEquals(length1, length2);
assertTrue(dt < 1000000); // 1000000 nanos = 1 millis
}
}
Just one detail: for the tests above to work, I added the following line inside the LengthWithCache#determineLengthPlusOne(String) method, in order to simulate the real-world scenario where the computation takes some time:
try { Thread.sleep(100); } catch (InterruptedException ignore) {}
Based on the proposal by krzyk here is my fully working solution:
The calculator itself:
public class LengthPlusOneCalculator {
public int calculateLengthPlusOne(String string) {
return string.length() + 1;
}
}
The separate caching mechanism:
public class LengthPlusOneCache {
private LengthPlusOneCalculator lengthPlusOneCalculator;
private java.util.Map<String, Integer> lengthPlusOneCache = new java.util.HashMap<String, Integer>();
public LengthPlusOneCache(LengthPlusOneCalculator lengthPlusOneCalculator) {
this.lengthPlusOneCalculator = lengthPlusOneCalculator;
}
public int calculateLenghtPlusOne(String string) {
Integer cachedStringLenghtPlusOne = lengthPlusOneCache.get(string);
if (cachedStringLenghtPlusOne != null) {
return cachedStringLenghtPlusOne;
}
int stringLenghtPlusOne = lengthPlusOneCalculator.calculateLengthPlusOne(string);
lengthPlusOneCache.put(string, new Integer(stringLenghtPlusOne));
return stringLenghtPlusOne;
}
}
The unit test for checking the LengthPlusOneCalculator:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class LengthPlusOneCalculatorTest {
#Test
public void testCalculateLengthPlusOne() {
LengthPlusOneCalculator lengthPlusOneCalculator = new LengthPlusOneCalculator();
assertEquals(6, lengthPlusOneCalculator.calculateLengthPlusOne("apple"));
}
}
And finally, the unit test for LengthPlusOneCache, checking the number of invocations:
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
import org.junit.Test;
public class LengthPlusOneCacheTest {
#Test
public void testNumberOfInvocations() {
LengthPlusOneCalculator lengthPlusOneCalculatorMock = mock(LengthPlusOneCalculator.class);
when(lengthPlusOneCalculatorMock.calculateLengthPlusOne("apple")).thenReturn(6);
LengthPlusOneCache lengthPlusOneCache = new LengthPlusOneCache(lengthPlusOneCalculatorMock);
verify(lengthPlusOneCalculatorMock, times(0)).calculateLengthPlusOne("apple"); // verify that not called yet
assertEquals(6, lengthPlusOneCache.calculateLenghtPlusOne("apple"));
verify(lengthPlusOneCalculatorMock, times(1)).calculateLengthPlusOne("apple"); // verify that already called once
assertEquals(6, lengthPlusOneCache.calculateLenghtPlusOne("apple"));
verify(lengthPlusOneCalculatorMock, times(1)).calculateLengthPlusOne("apple"); // verify that not called again
}
}
We can safely do the mocking mechanism, as we are already convinced that the mocked class works properly, using its own unit tests.
Normally this is built into a build system; this example can be complied and run from command line as follows (files junit-4.10.jar and mockito-all-1.9.5.jar have to be copied to the working directory):
javac -cp .;junit-4.10.jar;mockito-all-1.9.5.jar *.java
java -cp .;junit-4.10.jar org.junit.runner.JUnitCore LengthPlusOneCalculatorTest
java -cp .;junit-4.10.jar;mockito-all-1.9.5.jar org.junit.runner.JUnitCore LengthPlusOneCacheTest
However, I'm still not fully satisfied with this approach. My issues are the following:
Function calculateLengthPlusOne is mocked. I would prefer such a solution where a mocking or whatever framework just calculates the number of invocations, but the original code runs. (Somehow mentioned by davidhxxx, however I do not find also that a perfect one.)
The code became a bit over-complicated. This is not the way one would create normally. Therefore this approach is not adequate if the original code is not of our fully control. This could be a constraint in reality.
Normally I would make function calculateLengthPlusOne static. This approach does not work in such a case. (But maybe my Mockito knowledge is weak.)
If some could address any of these issues, I would really appreciate it!
When recording an expectation that returns the value of a field, I would expect the returned value to be the value of the field when the actual method was invoked (value of the reference), as opposed to the field's value when the expectation was recorded.
This is the class under test (actually 2 of them):
public class ListObservingCache<T> extends ObservingCache {
public ListObservingCache(Supplier<List<T>> syncFunc, int intervalMillis) {
super(syncFunc, intervalMillis);
}
#SuppressWarnings("unchecked")
#Override
public List<T> getItems() {
return items != null ? Collections.unmodifiableList((List<T>) items) : null;
}
}
public abstract class ObservingCache {
private static final int DEFAULT_CACHE_REFRESH_INTERVAL = 10 * 60 * 1000; // 10 minutes
private static int DEFAULT_CACHE_INITIAL_DELAY = 10 * 60 * 1000; // 10 minutes
private static final int DEFAULT_THREAD_POOL_SIZE = 5;
private static ScheduledExecutorService executor;
protected Object items;
protected ObservingCache(Supplier<? extends Object> syncFunc) {
this(syncFunc, DEFAULT_CACHE_REFRESH_INTERVAL);
}
protected ObservingCache(Supplier<? extends Object> syncFunc, int intervalMillis) {
if (executor == null || executor.isShutdown()) {
executor = Executors.newScheduledThreadPool(DEFAULT_THREAD_POOL_SIZE);
}
Runnable task = () -> {
Object result = syncFunc.get();
if (result != null) {
items = result;
}
};
task.run(); // First run is blocking (saves a lot of trouble later).
executor.scheduleAtFixedRate(task, DEFAULT_CACHE_INITIAL_DELAY, intervalMillis, TimeUnit.MILLISECONDS);
}
public abstract Object getItems();
}
Here is my test class:
public class ListObservingCacheTest {
List<Integer> provList; // <-- The field I wish to use instead of the "willReturnList()" method
#Mocked
DummyTask mockTask;
#BeforeClass
public static void setupClass() {
ObservingCache.DEFAULT_CACHE_INITIAL_DELAY = 100;
}
#AfterClass
public static void tearDownClass() {
ExecutorService toShutDown = (ExecutorService) getField(ObservingCache.class, "executor");
toShutDown.shutdown();
}
#Before
public void setUp() {
mockTask = new DummyTask(); // Empty list
}
#Test
public void testBasic() throws Exception {
willReturnList(Arrays.asList(1, 2));
ListObservingCache<Integer> obsCache = new ListObservingCache<Integer>(() -> mockTask.acquireList(), 300);
assertEquals(Arrays.asList(1, 2), obsCache.getItems());
willReturnList(Arrays.asList(3, 4, 5));
assertEquals(Arrays.asList(1, 2), obsCache.getItems()); // ObservingCache should still returns the former list because its interval hasn't passed yet
Thread.sleep(300);
assertEquals(Arrays.asList(3, 4, 5), obsCache.getItems()); // ObservingCache should now return the "new" list, as its interval has passed and the task has been executed again
}
/**
* Instructs the mock task to return the specified list when its
* acquireList() method is called
*/
private void willReturnList(List<Integer> list) {
new Expectations() {{ mockTask.acquireList(); result = list; }};
}
/**
* Simulates an ObservingCache "real-life" task. Should never really be
* called (because it's mocked).
*/
class DummyTask {
private List<Integer> list;
public List<Integer> acquireList() {
return list;
}
}
}
This test passes, but I would like a more elegant way to set the expectation for the return value of the acquireList() method, as this kind of "willReturn" methods would become a maintenance nightmare once I have more than one of these in the same class.
I'm looking for something similar to the mockito-syntax command:
when(mockTask.acquireList()).thenReturn(provList);
This should always return the current value of the provList field (as opposed to its value when the expectation was recorded).
EDIT:
After going through the documentation, I came up with a solution, using delegates:
new Expectations() {{
mockTask.acquireList();
result = new Delegate<List<Integer>>() {
List<Integer> delegate() {
return provList; // The private field
}
};
}};
There are 2 problems with this approach:
1. It's not elegant
2. The List<Integer> delegate() method causes a compile-time warning:
The method delegate() from the type new Delegate>(){} is never
used locally
Therefore, still looking for another solution
The problem the OP is trying to "solve" is this: how to simplify the writing of multiple tests in a single test method, when the code under test (here, the obsCache.getItems() method) and the verifications to perform are the same, but the input values are different.
So, this is really a question about how to properly write tests. The basic form of a well-written test is described by the "Arrange-Act-Assert" (AAA) pattern:
#Test
public void exampleOfAAATest() {
// Arrange: set local variables/fields with input values,
// create objects and/or mocks, record expectations.
// Act: call the code to be tested; normally, this is *one* method
// call only.
// Assert: perform a number of assertions on the output, and/or
// verify expectations on mocks.
}
#Test
public void exampleOfWhatisNotAnAAATest() {
// First "test":
// Arrange 1
// Act
// Assert 1
// Second "test":
// Arrange 2 (with different inputs)
// Act again
// Assert 2
// ...
}
Obviously, tests like the second one above are regarded as bad practice, and should not be encouraged.
EDIT: added full test class (below) for the real CUT.
public final class ListObservingCacheTest
{
#Mocked DummyTask mockTask;
final int refreshIntervalMillis = 30;
final List<Integer> initialItems = asList(1, 2);
final List<Integer> newItemsAfterRefreshInterval = asList(3, 4, 5);
#Before
public void arrangeTaskOutputForMultipleCalls() {
new Expectations() {{
mockTask.acquireList();
result = initialItems;
result = newItemsAfterRefreshInterval;
}};
// A trick to avoid a long initial delay before the scheduled task is first
// executed (a better solution might be to change the SUT to read the
// initial delay from a system property).
new MockUp<ScheduledThreadPoolExecutor>() {
#Mock
ScheduledFuture<?> scheduleAtFixedRate(
Invocation inv,
Runnable command, long initialDelay, long period, TimeUnit unit
) {
return inv.proceed(command, 0, period, unit);
}
};
}
#After
public void shutdownTheExecutorService() {
ScheduledExecutorService executorService =
Deencapsulation.getField(ObservingCache.class, ScheduledExecutorService.class);
executorService.shutdown();
}
#Test
public void getTheInitialItemsImmediatellyAfterCreatingTheCache() throws Exception {
// Arrange: empty, as there is nothing left to do beyond what the setup method
// already does.
// Act:
ListObservingCache<Integer> obsCache =
new ListObservingCache<>(() -> mockTask.acquireList(), refreshIntervalMillis);
List<Integer> items = obsCache.getItems();
// Assert:
assertEquals(initialItems, items);
}
#Test
public void getTheSameItemsMultipleTimesBeforeTheCacheRefreshIntervalExpires() throws Exception {
// Act:
ListObservingCache<Integer> obsCache =
new ListObservingCache<>(() -> mockTask.acquireList(), refreshIntervalMillis);
List<Integer> items1 = obsCache.getItems();
List<Integer> items2 = obsCache.getItems();
List<Integer> itemsIfTaskGotToBeCalledAgain = mockTask.acquireList();
List<Integer> items3 = obsCache.getItems();
// Assert:
assertEquals(initialItems, items1);
assertEquals(initialItems, items2);
assertEquals(initialItems, items3);
assertEquals(newItemsAfterRefreshInterval, itemsIfTaskGotToBeCalledAgain);
}
#Test
public void getNewItemsAfterTheCacheRefreshIntervalExpires() throws Exception {
// Act:
ListObservingCache<Integer> obsCache =
new ListObservingCache<>(() -> mockTask.acquireList(), refreshIntervalMillis);
List<Integer> items1 = obsCache.getItems();
Thread.sleep(refreshIntervalMillis);
List<Integer> items2 = obsCache.getItems();
// Assert:
assertEquals(initialItems, items1);
assertEquals(newItemsAfterRefreshInterval, items2);
}
}
When new Expectations() is used in code, an instance of Expectations is created with providedInt value. So, though providedInt is changed in testRegisterInt(), state of Expectations instance does not change. You can try setter to change the result of Expectations.
Ideally, there should not be any logic in stubs. I would rather create multiple stubs in multiple test methods(if its really needed) or use anyInteger sort of stuff based on my needs.
my code:
#RunWith(Parameterized.class)
public class FreshResultCompareRunner2 {
//This is called before #BeforeClass !
#Parameterized.Parameters
public static Collection getRequests() throws IOException {
injector = Guice.createInjector(new MainModule());
initStaticFromInjector();
initTestInput();
return OrganizeTestParameterizedInput();
}
private static void initTestInput() throws IOException {
}
private static Collection OrganizeTestParameterizedInput() {
Object[] objectMatrix = new Object[100];
for (int i = 0; i < 100; i++) {
objectMatrix[i] = i;
}
return Arrays.asList(objectMatrix);
}
returns the following exception:
getRequests() must return an Iterable of arrays
how can i run the parameterized junit with increasing int only as input param?
say run the same test for i=0 ...100 ?
update
I have tried
//This is called before #BeforeClass !
#Parameterized.Parameters
public static Collection<int[]> getParameters() {
injector = Guice.createInjector(new MainModule());
initStaticFromInjector();
int numOfChunks = 3;//routingResponseShortRepository.getNumOfBaseLineChunks();
//might be less
int totalResponses = numOfChunks * globalSettings.requestsChunkSize;
Collection<int[]> params = new ArrayList<>(totalResponses);
for(int i = 1; i <= totalResponses; ++i) {
params.add(new int[] { i });
}
return params;
}
//takes the next matrix row from OrganizeTestParameterizedInput()
public FreshResultCompareRunner2(int responseId) {
this.responseId = responseId;
}
and still get an error:
java.lang.Exception: com.waze.routing.automation.runners.FreshResultCompareRunner2.getParameters() must return an Iterable of arrays.
at org.junit.runners.Parameterized.parametersMethodReturnedWrongType(Parameterized.java:343)
Junit 4.12+ does not has this restriction anymore. So if you develop your tests with JUnit 4.12+ and then execute those test with 4.11- you will also get this error message.
See JUnit 4.12 release notes for more details.
For parametrized tests, JUnit passed the test parameters to the constructor of the test class. Because a constructor can take more than one single argument, JUnit expects every parameter set to be an array. The elements of the array must conform to the constructor arguments.
So your configuration method must return an Iterable of arrays, e.g. Collection<Object[]>. In your case, you just have one single parameter per run, so your array will have a length of 1:
#Parameterized.Parameters
public static Collection<Object[]> getParameters() {
Collection<Object[]> params = new ArrayList<>(100);
for(int i = 1; i <= 100; ++i) {
params.add(new Object[] { i });
}
return params;
}
Also note that your configuration method should never do any initialization as your method seems to do! Initialization is solely done in #Before or #BeforeClass!
How can I test the following class using JUnit testing. I am new to unit testing I just need a push to start
public class ComponentComparator implements Comparator< Component >
{
#Override
public int compare ( final Component c1, final Component c2 )
{
if ( c1.getBandwidthWithHeader() > c2.getBandwidthWithHeader() )
{
return -1;
}
else if ( c1.getBandwidthWithHeader() < c2.getBandwidthWithHeader() )
{
return 1;
}
return 0;
}
}
Part of the component class is, there is no constructor for this class
public class Component
{
private float bandwidthwithHeader;
public void setBandwidthWithHeader ( float bandwidthwithHeader )
{
this.bandwidthwithHeader = bandwidthwithHeader;
}
public float getBandwidthWithHeader ()
{
return this.bandwidthwithHeader;
}
}
You should go through some tutorial on JUnit.
Morfic's comment points to a good tutorial.
To begin with helping you with this - there are three possible return values from the comparator -> wrote a case for each one.
import org.junit.Assert;
import org.junit.Test;
public class ComponentComparatorTest {
#Test
public void testCompare() throws Exception {
ComponentComparator comparator = new ComponentComparator();
Assert.assertEquals(comparator.compare(new Component(1), new Component(1)), 0);
Assert.assertEquals(comparator.compare(new Component(2), new Component(1)), -1);
Assert.assertEquals(comparator.compare(new Component(1), new Component(2)), 1);
}
}
I am using a dummy class
public class Component {
int bandwidth;
public Component(int bandwidth) {
this.bandwidth = bandwidth;
}
public int getBandwidthWithHeader(){
return bandwidth;
}
}
The unit test should test all possible outcomes.
A comparator has three success outcomes.
You need to decide how you want to handle null parameter values (your current solution: NullPointerException).
Here is a unit test of your current comparator:
public class Component
{
private int bandwidthWithHeader;
public int getBandwidthWithHeader()
{
return bandwidthWithHeader;
}
public void setBandwidthWithHeader(final int newValue)
{
bandwidthWithHeader = newValue;
}
}
public class ComponentTest
{
private final ComponentComparator componentComparator = new ComponentComparator();
#Test
public void negative1()
{
Component two = new Component();
try
{
componentComparator.compare(null, two);
fail("Expected exception was not thrown");
}
catch(NullPointerException exception)
{
// The NullPointerException is the expected result.
assertTrue(true);
}
}
#Test
public void negative2()
{
Component one = new Component();
try
{
componentComparator.compare(one, null);
fail("Expected exception was not thrown");
}
catch(NullPointerException exception)
{
// The NullPointerException is the expected result.
assertTrue(true);
}
}
#Test
public void negative3()
{
try
{
componentComparator.compare(null, null);
fail("Expected exception was not thrown");
}
catch(NullPointerException exception)
{
// The NullPointerException is the expected result.
assertTrue(true);
}
}
#Test
public void positive1()
{
Component one = new Component();
Component two = new Component();
// test one < two
one.setBandwidthWithHeader(7);
two.setBandwidthWithHeader(16);
assertEquals(-1, componentComparator.compare(one, two);
// test two < one
one.setBandwidthWithHeader(17);
two.setBandwidthWithHeader(16);
assertEquals(1, componentComparator.compare(one, two);
// test two == one
one.setBandwidthWithHeader(25);
two.setBandwidthWithHeader(25);
assertEquals(0, componentComparator.compare(one, two);
}
}
How about something like this:
package mypackage;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class ComponentComparatorTestCase {
#Test
public void testCompareExpectZero() {
ComponentComparator sut = new ComponentComparator();
// create some components to test with
Component c1 = new Component();
Component c2 = new Component();
// execute test
int result = sut.compare(c1, c2);
// verify
assertEquals("Did not get expected result.", result, 0);
}
}
There are numerous tests you should do for any Comparator implementation.
First off, there is the fact that a Comparator should define (as stipulated in the Comparator contract) a total order on the given type.
This comes down to 3 things :
the order should be antisymmetric : if a ≤ b and b ≤ a then a = b
the order should be transitive : if a ≤ b and b ≤ c then a ≤ c
the order should be total : either a ≤ b or b ≤ a
Secondly, a Comparator implementation may choose to accept null values. So we need tests that verify whether null values are treated correctly, if accepted. Or if they are not accepted that they properly result in a NullPointerException being thrown.
Lastly, if the type being compared may be subclassed, it is worth testing that the comparator properly compares instances of various subclasses mixed with instances of the class itself. (You may need to define some subclasses in test scope for these tests)
As these tests tend to repeat for every Comparator implementation, it may be worth extracting them in an abstract test superclass.