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.
Related
My program is structured as follows: a class that represents an atomic concept which is essentially a String and another class that is made of a list of general concepts. Both classes extends the class Concept that is an abstract class, this means that in the list I could have both atomic concepts and intersection of concepts arbitrary nested.
Each concept, atomic or composed, is printed out by toString method.
Roughly speaking, this is based on this context-free grammar:
C : atom | (C and)+ C
Where C is the abstract class Concept, atom is AtomicConcept and (C and)+ C is Intersection.
This is the AtomicConcept class:
public class AtomicConcept extends Concept{
private String atomicConceptName;
public AtomicConcept(String c) {
this.atomicConceptName = c;
}
#Override
public String toString() {
return atomicConceptName;
}
}
This is che ConceptIntersection class:
import java.util.List;
public class ConceptIntersection extends Concept{
private List<Concept> list;
public ConceptIntersection(List<Concept> l) throws Exception {
if(l.size()>1)
{
this.list = l;
}
else
{
throw new Exception("Intersection needs at least two concepts!");
}
}
public String toString()
{
return Utils.conceptIntersection + Utils.lparen + Utils.splitConcepts(list) + Utils.rparen;
}
}
As you can see in toString function, I also created a method called splitConcepts that takes in input a list of general concepts and returns one string made of each concept separated by comma.
public static String splitConcepts(List<Concept> list)
{
String result = "";
for (Concept item : list) {
System.out.println(item);
result += item.toString() + comma;
}
result = result.substring(0, result.length() - 1);
return result;
}
Where is the problem?
I have trouble with this function because when I call a nested intersection in another one, this function never ends!
One example:
public static void main(String[] args) throws DLRException {
// TODO Auto-generated method stub
AtomicConcept atom = new AtomicConcept("one");
AtomicConcept at = new AtomicConcept("two");
List<Concept> list = new LinkedList<Concept>();
list.add(at);
list.add(atom);
DLRConceptIntersection intersection = new DLRConceptIntersection(list);
System.out.println(intersection); // works fine
list.add(intersection);
DLRConceptIntersection intersection2 = new DLRConceptIntersection(list);
System.out.println(intersection2); //loop never ends!
}
Is a correct approach to fix this problem?
You have a circular reference :
DLRConceptIntersection intersection = new DLRConceptIntersection(list);
list.add(intersection);
This causes the intersection's List to contain a reference to the same instance referred by intersection, which is why toString() run into infinite recursion.
I'm assuming you didn't intend intersection and intersection2 to share the same List.
You can avoid it if you create a copy of the List in the DLRConceptIntersection constructor:
public ConceptIntersection(List<Concept> l) throws Exception {
if(l.size()>1) {
this.list = new ArrayList<>(l);
} else {
throw new Exception("Intersection needs at least two concepts!");
}
}
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.
I have my existing framework built up using Jfunc which provides a facility to continue exection even when one of the asserts in the test case fails. Jfunc uses junit 3.x framework. But now we are migrating to junit4 so I can't use Jfunc anymore and have replaced it with junit 4.10 jar.
Now the problem is since we have extensively used jfunc in our framework, and with junit 4 we want to make our code continue the execution even when one of the asserts fails in a test case.
Does anyone has any suggestion/idea for this, i know in junit the tests needs to be more atomic i.e. one assert per test case but we can't do that in our framework for some reason.
You can do this using an ErrorCollector rule.
To use it, first add the rule as a field in your test class:
public class MyTest {
#Rule
public ErrorCollector collector = new ErrorCollector();
//...tests...
}
Then replace your asserts with calls to collector.checkThat(...).
e.g.
#Test
public void myTest() {
collector.checkThat("a", equalTo("b"));
collector.checkThat(1, equalTo(2));
}
I use the ErrorCollector too but also use assertThat and place them in a try catch block.
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
#Rule
public ErrorCollector collector = new ErrorCollector();
#Test
public void calculatedValueShouldEqualExpected() {
try {
assertThat(calculatedValue(), is(expected));
} catch (Throwable t) {
collector.addError(t);
// do something
}
}
You can also use assertj - soft assertion
#Test
public void testCollectErrors(){
SoftAssertions softly = new SoftAssertions();
softly.assertThat(true).isFalse();
softly.assertThat(false).isTrue();
// Don't forget to call SoftAssertions global verification !
softly.assertAll();
}
Also exist other way to use it without manually invoke softly.assertAll();
with rule
with autoclosable
Using the static assertSoftly method
Use try/finally blocks. This worked in my case:
...
try {
assert(...)
} finally {
// code to be executed after assert
}
...
Try - catch, in "try" use the assertion, in "catch" add the possible error to collection.
Then throw the exception at the end of test, in tearDown().
So if there will be fail/error in assert, it will be catched and test will continue.
(The collection in example is static, you can also make new instance in setUp() for each #Test)
public static List<String> errors = new ArrayList<>();
try {
//some assert...
}
catch (AssertionError error) {
errors.add(error.toString());
}
#After
public void tearDown() {
try {
if (!errors.isEmpty()) {
throw new AssertionError(errors);
}
}
finally {
//empty list because it's static, alternatively make instance for each test in setUp()
errors.clear();
}
}
I created my own simple assertions class. Easy to extend with your use-cases:
public class MyEquals {
public static void checkTestSummary(MyTestSummary myTestSummary) {
final List<MyTestResult> conditions = myTestSummary.getTestResults();
final int total = conditions.size();
final boolean isSuccessful = myTestSummary.isSuccessful();
if (isSuccessful) {
System.out.println(format("All [%s] conditions are successful!", total));
} else {
final List<MyTestResult> failedConditions = conditions.stream().filter(MyTestResult::isTestResult).collect(Collectors.toList());
System.out.println(format("\nNot yet.. [%s out of %s] conditions are failed", failedConditions.size(), total));
}
if (!isSuccessful) {
for (int i = 0; i < total; i++) {
final MyTestResult myTestResult = conditions.get(i);
if (myTestResult.isTestResult()) {
System.out.println(format(" Success [%s of %s] => Expected %s Actual %s Good!", i + 1, total, myTestResult.getExpected(), myTestResult.getActual()));
} else {
System.out.println(format("!! Failed [%s of %s] => Expected %s Actual %s", i + 1, total, myTestResult.getExpected(), myTestResult.getActual()));
}
}
}
assertTrue(isSuccessful);
}
public static void myAssertEquals(MyTestSummary myTestSummary, Object expected, Object actual) {
if (checkEquals(expected, actual)) {
assertEquals(expected, actual);
myTestSummary.addSuccessfulResult(expected, actual);
} else {
myTestSummary.addFailedResult(expected, actual);
myTestSummary.setSuccessful(false);
}
}
public static boolean checkEquals(Object value1, Object value2) {
if (value1 == null && value2 == null) {
return true;
} else if (value1 != null && value2 == null) {
return false;
} else if (value1 == null && value2 != null) {
return false;
} else if (value1 != null && value2 != null) {
return value1.equals(value2);
}
return false;
}
}
#Builder
#Value
public class MyTestResult {
String expected;
String actual;
boolean testResult;
}
#Data
public class MyTestSummary {
private boolean successful = true;
private List<MyTestResult> testResults = new ArrayList<>();
public MyTestSummary() {
}
public void addSuccessfulResult(Object expected, Object actual) {
getTestResults().add(MyTestResult.builder()
.expected(String.valueOf(expected))
.actual(String.valueOf(actual))
.testResult(true)
.build()
);
}
public void addFailedResult(Object expected, Object actual) {
getTestResults().add(MyTestResult.builder()
.expected(String.valueOf(expected))
.actual(String.valueOf(actual))
.testResult(false)
.build()
);
}
}
Usage in the junit test
#Test
public void testThat() {
MyTestSummary myTestSummary = new MyTestSummary();
myAssertEquals(myTestSummary, 10, 5 + 5);
myAssertEquals(myTestSummary, "xxx", "x" + "x");
checkTestSummary(myTestSummary);
}
Output:
Not yet.. [1 out of 2] conditions are failed
Success [1 of 2] => Expected 10 Actual 10 Good!
!! Failed [2 of 2] => Expected xxx Actual xx
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
Expected :true
Actual :false
Another option is the observable pattern in conjunction with lambda expressions. You can use something like the above.
public class MyTestClass {
private final List<Consumer<MyTestClass>> AFTER_EVENT = new ArrayList<>();
#After
public void tearDown() {
AFTER_EVENT.stream().forEach(c -> c.accept(this));
}
#Test
public void testCase() {
//=> Arrange
AFTER_EVENT.add((o) -> {
// do something after an assertion fail.
}));
//=> Act
//=> Assert
Assert.assertTrue(false);
}
}
I have 2 classes e.g. A and B.
These classes have a couple of getter/setter methods with the same name.
Now in the code I do the following:
if(obj.getClassName().equals(A.class.getName())){
A a = (A) obj;
String result = a.getInfo();
}
else if(obj.getClassName().equals(B.class.getName())){
B a = (B) obj;
String result = a.getInfo();
}
I was wondering if there is a way to call the getInfo avoiding the if statements.
Note: I can not refactor the classes to use inheritence or something else.
I was just interested if there is a trick in java to avoid the if statements.
Unless you want to use reflection, no. Java treats two types which happen to declare the same method (getInfo()) as entirely separate, with entirely separate methods.
If you've got commonality, you should be using a common superclass or a common interface that both of them inherit. You've tagged the question "design-patterns" - the pattern is to use the tools that the language provides to show commonality.
As Eng.Fouad shows, using instanceof is simpler anyway - and better, as it means your code will still work with subclasses of A or B.
You can isolate this ugliness, of course, by putting it in a single place - either with a facade class which can be constructed from either an A or a B, or by having a single method which performs this check, and then calling that from multiple places.
If you can't use inheritance and want to avoid if statements (even using instanceof)... well... the best you can do is wrap the check, cast and call in a function to avoid code duplication... otherwise there's no way to do this.
You need reflection. here is my complete example.
Class A
package a;
public class A {
String info;
public String getInfo() {
System.out.println("A getInfo");
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
Class B
package a;
public class B {
String info;
public String getInfo() {
System.out.println("B getInfo");
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
Test Class
package a;
import java.lang.reflect.Method;
public class TestAB {
public static void main(String[] args) {
A a= new A();
doSth(a);
}
private static void doSth(Object obj) {
Class c = obj.getClass();
Method m;
try {
m = c.getMethod("getInfo", new Class[] { });
String result = (String) m.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
See this line :
Class c = obj.getClass();
and
m = c.getMethod("getInfo", new Class[] { });
and
String result = (String) m.invoke(obj);
There is no if statements
If obj is declared as either A or B, you can use overloaded methods. (A good argument for type safety.) Here's a test that illustrates this:
import static org.junit.Assert.*;
import org.junit.Test;
public class FooTest {
class A {
public String getInfo() {
return "A";
}
}
class B {
public String getInfo() {
return "B";
}
}
public String doBarFor(A a) {
return a.getInfo();
}
public String doBarFor(B b) {
return b.getInfo();
}
public String doBarFor(Object obj) {
throw new UnsupportedOperationException();
}
#Test
public void shouldDoBarForA() {
A a = new A();
assertEquals("A", doBarFor(a));
}
#Test
public void shouldDoBarForB() {
B b = new B();
assertEquals("B", doBarFor(b));
}
#Test(expected = UnsupportedOperationException.class)
public void shouldFailIfDeclaredAsObject() {
Object a = new A();
assertEquals("A", doBarFor(a)); // exception thrown
}
}
How about:
String result = null;
if(obj instanceof A)
{
result = ((A) obj).getInfo();
}
else if(obj instanceof B)
{
result = ((B) obj).getInfo();
}
Refer to : this tutorial if this is what you were trying to achieve.
If obj is an Object, you'll need to check. If you don't want to use an if-statement, you can try just casting and catch the exception:
String result = null;
try {
result = ((A)obj).getInfo();
}
catch(ClassCastException e1) {
try {
result = ((B)obj).getInfo();
}
catch(ClassCastException e2) {
// do something else
}
}
Another thing you can do is make both classes implement an Interface then check for just that Interface, something like:
public interface HasInfo
{
public String getInfo();
}
Then add implements HasInfo in the class definition for A and B. Then you can just check (or cast) to HasInfo.
In Java you can use a dot as a scope resolution operator with static methods. Try something like this:
String a_info = A.getInfo();
String b_info = B.getInfo();
With objects, if two interfaces really have the same method with the same parameters and the same return type, why must they be treated differently? Take a look here for some more insight into the problem.
Good luck.