I am writing test cases for this code.
But I am not able to write junit test cases for this. I am having problem to write junit test cases for this.
Please help to write mockito or junit test case for this.
public class BasicCacheManager implements CacheManager {
private ConcurrentHashMap<String, BasicCache> cacheMap;
private String defaultCache;
public BasicCacheManager() {
this.cacheMap = new ConcurrentHashMap<String, BasicCache>();
}
public BasicCacheManager(List<String> cacheNames) {
this.cacheMap = new ConcurrentHashMap<String, BasicCache>();
addCache(cacheNames);
}
#Override
public BasicCache getCache(){
return getCache(defaultCache);
}
#Override
public BasicCache getCache(String name) {
return cacheMap.get(name);
};
#Override
public void addCache(BasicCache cache) {
cacheMap.put(cache.getName(), cache);
};
#Override
public void removeCache(String name) {
cacheMap.remove(name);
};
#Override
public void removeAll() {
cacheMap = new ConcurrentHashMap<String, BasicCache>();
};
#Override
public boolean cacheExists(String name) {
return cacheMap.containsKey(name);
};
#Override
public void removeElement(String cacheName, String element){
BasicCache cache = getCache(cacheName);
if(cache != null){
cache.remove(element);
}
}
// added final to avoid any child classes from overriding this method
private final void addCache(List<String> cacheNames) {
for (String cacheName : cacheNames) {
BasicCache cache = new BasicCache(cacheName);
addCache(cache);
}
}
}
You don't need mocking here.
Your CUT (class under test) has very clear semantics; and interfaces that basically guide you into writing testcases. What you have to do: create objects of your cache class; and then use its methods to modify it; and asserts to verify.
Example:
#Test
public void testNewCacheIsEmpty() {
BasicCache underTest = new BasicCache();
assertThat(underTest.isEmpty(), is(true));
}
(in case you dont have an isEmpty() yet, you could add that one as package-protected method; just to allow for such tests).
Then you write other tests; for example that make sure that adding a certain cache-key ... actually does what you expect that to do.
So, the primary thing to understand here: you should design your whole cache so that you can test it ... without knowing what exactly it is doing.
Of course, you could create a mocked ConcurrentHashMap object and pass that into your class; to verify that exactly those calls that you expect for some operation to take place really happen. But that means: testing implementation details. And you want to avoid that if possible.
And just for the record: your field defaultCache doesn't make any sense in the code you are showing. It is null initially, there is no setter for it; so it has absolutely no purpose.
Related
Say I have the following class:
public class ProblematicObject {
public static void methodToTest() {
SomeDependency dep = DependencyGetter.getDependency(SomeDependency.class);
dep.doStuff();
}
}
Is it an acceptable practice to modify and add methods to this class for the sake of making unit testing cleaner (aka avoiding PowerMock)? Here's what the class above would look like:
public class ProblematicObject {
// new
private static SomeDependency dep;
// updated
public static void methodToTest() {
getSomeDependency().doStuff();
}
// new
private SomeDependency getSomeDependency() {
if (this.dep == null) {
return DependencyGetter.getDependency(SomeDependency.class);
}
return dep;
}
// new, only used for testing, not in any impl code
#Deprecated
protected void setDependencyGetter(SomeDependency dep) {
this.dep = dep;
}
}
I seem to recall reading somewhere that adding methods for the sake of testing (instead of refactoring the problematic class) is looked down upon.
In this particular example, you are in fact improving your class design by making it testable.
This new unit test made you think from the point of view of the client of ProblematicObject and made you provide a way to inject that dependency.
Preconditions
I have the following class (fictional, just for demonstrating the problem):
public class MySingleton {
private static MySingleton sMySingleton;
private static List<String> sItemList;
private MySingleton(List<String> list) {
sItemList = list;
}
public static MySingleton getInstance(List<String> list) {
if (sMySingleton == null) {
sMySingleton = new MySingleton(list);
}
return sMySingleton;
}
public void addItem(String item) {
sItemList.add(item);
}
public void removeItem(String item) {
sItemList.remove(item);
}
}
And an according test class:
public class MySingletonTest {
private MySingleton mInstance;
private List<String> mList;
#Before
public void setup() {
mList = mock(List.class);
mInstance = MySingleton.getInstance(mList);
}
#Test
public void testAddItem() throws Exception {
String item = "Add";
mInstance.addItem(item);
verify(mList, times(1)).add(item);
}
#Test
public void testRemoveItem() throws Exception {
String item = "Remove";
mInstance.removeItem(item);
verify(mList, times(1)).remove(item);
}
}
Problem
If I now execute the complete test class, Mockito tells me for the test testRemoveItem() that there were 0 interactions with the mock.
How is that possible?
Note:
Please do not start of a discussion about the sense singletons.
This question is about Mockito and why its not working.
JUnit creates a new test class instance for every single test, which Mockito populates with a new mock instance for every single test. However, your singleton only ever initializes itself once, meaning that mList == MySingleton.sItemList during the first test but mList != MySingleton.sItemList for every test after that.
In other words, the interaction is happening, but by the second test, you're checking the wrong mock.
Though I know you're not here to debate the merits of this type of singleton, bear in mind that you might have a hard time replacing the instance in tests if you do it this way. Instead, consider making the singleton's constructor available (only) to your tests, and keeping the List (or other state) within the instance. That way you can create a brand new "Singleton" for every individual test.
Class I want to test:
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
public class Subject {
private CacheLoader<String, String> cacheLoader = new CacheLoader<String, String>() {
#Override
public String load(String key)
throws Exception {
return retrieveValue(key);
}
};
private LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.build(cacheLoader);
public String getValue(String key) {
return cache.getUnchecked(key);
}
String retrieveValue(String key) {
System.out.println("I should not be called!");
return "bad";
}
}
Here's my test case
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class SubjectTest {
String good = "good";
#Spy
#InjectMocks
private Subject subject;
#Test
public void test() {
doReturn(good).when(subject).retrieveValue(anyString());
assertEquals(good, subject.getValue("a"));
}
}
I got
org.junit.ComparisonFailure:
Expected :good
Actual :bad
This comes down to the implementation of the spy. According to the docs, the Spy is created as a copy of the real instance:
Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it. So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their effect on real instance state. The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any effects on the real instance.
It seems to be a shallow copy. As a result, as far as my debugging shows, the CacheLoader is shared between the copy and the original object, but its reference to its enclosing object is the original object, not the spy. Therefore the real retrieveValue is called instead of the mocked one.
I'm not sure offhand what the best way to resolve this would be. One way for this specific example would be to invert the CacheLoader dependency (i.e. pass it into Subject instead of Subject defining it internally), and mock that instead of Subject.
Mark Peters did a great job diagnosing and explaining the root cause. I can think of a couple workarounds:
Move cache (re)initialization into a separate method.
By calling new CacheLoader from within the spy, the anonymous inner class is created with a reference to the spy as the parent instance. Depending on your actual system under test, you may also benefit from getting the cache creation out of the constructor path, especially if there's any heavy initialization or loading involved.
public class Subject {
public Subject() {
initializeCache();
}
private LoadingCache<String, String> cache;
#VisibleForTesting
void initializeCache() {
cache = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
#Override
public String load(String key) throws Exception {
return retrieveValue(key);
}
});
}
/* ... */
}
#Test
public void test() {
subject.initializeCache();
doReturn(good).when(subject).retrieveValue(anyString());
assertEquals(good, subject.getValue("a"));
}
Make a manual override.
The root cause of your trouble is that the spy instance is different from the original instance. By overriding a single instance in your test, you can change behavior without dealing with the mismatch.
#Test
public void test() {
Subject subject = new Subject() {
#Override public String getValue() { return "good"; }
}
}
Refactor.
Though you can go for full DI, you may be able to just add a testing seam to the value function:
public class Subject {
private CacheLoader<String, String> cacheLoader = new CacheLoader<String, String>() {
#Override
public String load(String key) throws Exception {
return valueRetriever.apply(key);
}
};
private LoadingCache<String, String> cache =
CacheBuilder.newBuilder().build(cacheLoader);
Function<String, String> valueRetriever = new Function<String, String>() {
#Override
public String apply(String t) {
System.out.println("I should not be called!");
return "bad";
}
};
public String getValue(String key) {
return cache.getUnchecked(key);
}
}
#Test
public void test() {
subject = new Subject();
subject.valueRetriever = (x -> good);
assertEquals(good, subject.getValue("a"));
}
Naturally, depending on your needs, valueRetriever could be an entirely separate class, or you could accept an entire CacheLoader as a parameter.
I had same issue, for Mockito 1.9.5 possible solution may be to change method visibility to "protected". Honestly, I have no idea how it works, but still, error gone.
So I have small interface
public interface IPlayersStorage
{
// other methods...
public boolean addException(final String nick);
// other methods...
}
and class "PlayersStorage" that implements it: (only used part)
public class PlayersStorage implements IPlayersStorage
{
private static final PlayersStorage inst = new PlayersStorage();
private final Set<String> exceptions = new HashSet<>(50);
#Override
public boolean addException(final String nick)
{
return ! this.exceptions.add(nick);
}
public static PlayersStorage getStorage()
{
return inst;
}
}
And in some place I use that method using that code:
for (final String player : this.cfg.getStringList("Exceptions"))
{
PlayersStorage.getStorage().addException(player);
}
And ProGuard change it to:
for (Iterator localIterator1 = this.cfg.getStringList("Exceptions").iterator(); localIterator1.hasNext();)
{
localIterator1.next();
PlayersStorage.getStorage(); // it's get object, but don't do anything with it...
}
The only possible fix that I found, is add static method to PlayersStorage
public static boolean staticAddException(final String nick)
{
return inst.addException(nick);
}
And then use it (instead of old code)
for (final String player : this.cfg.getStringList("Exceptions"))
{
PlayersStorage.staticAddException(player);
}
Then works... (ProGuard keep method call) but adding static methods for every method from interface isn't good idea.
ProGuard only removes method invocations if they don't have any effect (doesn't seem to be the case here), or if you have specified -assumenosideffects for the methods. You should check your configuration and remove any such option.
Alternatively, your decompiler may be having problems decompiling the code. You should then check the actual bytecode with javap -c.
I need to test handleIn() method using Mockito.
However the code need to call this legacy code Util.getContextPDO which is a static method.
Note that in testing environment this Util.getContextPDO is always returns Exception, and I intend to bypass this Util.getContextPDO() by always return a dummy IPDO.
public class MyClass {
public IPDO getIPDO()
{
return Util.getContextPDO(); // note that Util.getContextPDO() is a static, not mockable.
}
public String handleIn(Object input) throws Throwable
{
String result = "";
IPDO pdo = getIPDO();
// some important business logic.
return result;
}
}
Initially I thought this achieveable by using spy() of the class "MyClass", so I can mock the return value of getIPDO(). Below is my initial effort using spy ()
#Test
public void testHandleIn() throws Exception
{
IPDO pdo = new PDODummy();
MyClass handler = new MyClass ();
MyClass handler2 = spy(handler);
when(handler2.getIPDO()).thenReturn(pdo);
PDOUtil.setPDO(pdo, LogicalFieldEnum.P_TX_CTGY, "test123");
IPDO pdoNew = handler2.getIPDO();
Assert.assertEquals("test123,(PDOUtil.getValueAsString(pdoNew, LogicalFieldEnum.P_TX_CTGY)));
}
However the when(handler2.getIPDO()).thenReturn(pdo); is throwing the Exception that I want to avoid ( because handler2.getIPDO() ) seems to call the real method.
Any idea on how to test this part of code?
A good technique for getting rid of static calls on 3rd party API is hiding the static call behind an interface.
Let's say you make this interface :
interface IPDOFacade {
IPDO getContextPDO();
}
and have a default implementation that simply calls the static method on the 3rd party API :
class IPDOFacadeImpl implements IPDOFacade {
#Override
public IPDO getContextPDO() {
return Util.getContextPDO();
}
}
Then it is simply a matter of injecting a dependency on the interface into MyClass and using the interface, rather than the 3rd party API directly :
public class MyClass {
private final IPDOFacade ipdoFacade;
public MyClass(IPDOFacade ipdoFacade) {
this.ipdoFacade = ipdoFacade;
}
private IPDO getIPDO() {
return ipdoFacade.getContextPDO();
}
public String handleIn(Object input) throws Throwable
{
String result = "";
IPDO pdo = getIPDO();
someImportantBusinessLogic(pdo);
return result;
}
...
}
In your unit test, you can then easily mock your own interface, stub it any way you like and inject it into the unit under test.
This
avoids the need to make private methods package private.
makes your tests more readable by avoiding partial mocking.
applies inversion of control.
decouples your application from a specific 3rd party library.
Changed my testing to :
#Test
public void testHandleIn() throws Exception
{
IPDO pdo = new PDODummy();
MyClass handler = new MyClass ();
MyClass handler2 = spy(handler);
doReturn(pdo ).when( handler2 ).getIPDO();
PDOUtil.setPDO(pdo, LogicalFieldEnum.P_TX_CTGY, "test123");
IPDO pdoNew = handler2.getIPDO();
Assert.assertEquals("test123,(PDOUtil.getValueAsString(pdoNew, LogicalFieldEnum.P_TX_CTGY)));
}
Solved after reading Effective Mockito.
when(handler2.getIPDO()).thenReturn(pdo);
Will actually call the method and then return pdo regardless.
Whereas:
doReturn(pdo).when(handler2).getIPDO();
Will return pdo without calling the getIPDO() method.