Mockito - Zero interactions with mock - Singleton - java

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.

Related

Skip null check in mockito

I am trying to write unit test cases for one of the methods in code.Below is the method
public boolean isValid() {
if(object == null)
return false
//do something here and return value.
}
The object is created by this method which is done before without getter setter method.
private Object returnObject() {
object = Axis2ConfigurationContextFactory.getConfigurationContext();
return object;
}
When I try to test isValid(), the object is always null, so it never goes in the code to do something.
I was checking if there is any way to skip that line or make the object not null. I also tried creating an object using returnObject method. But it uses Axis library classes which throws error if it does not find certain data. What can be done in this case? I am dealing with legacy code so any pointers would be helpful.
Edit : Adding test implementation.
#PowerMockIgnore({ "javax.xml.*", "org.w3c.dom.*", "javax.management.*" })
public class ClassTest {
private ClassTest classTestObj;
#BeforeMethod
public void callClassConstructor() {
classTestObj = //call class constructor
}
#BeforeClass
public void setUpClass() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public boolean isValidTest() {
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
As I mentioned in the before comment, you can make use of MockedStatic to mock the static method - https://javadoc.io/static/org.mockito/mockito-core/4.4.0/org/mockito/Mockito.html#static_mocks
So your code will somewhat look like the below one if you are making use of Mockito instead of PowerMockito.
#RunWith(MockitoJUnitRunner.class)
public class ClassTest
{
#Mock
private Object mockAxis2ConfigurationContextFactoryObject;
#Test
public boolean isValidTest() {
try (MockedStatic<Axis2ConfigurationContextFactory> mockedStatic = mockStatic(Axis2ConfigurationContextFactory.class)) {
mockedStatic.when(()->Axis2ConfigurationContextFactory.getConfigurationContext()).thenReturn(mockAxis2ConfigurationContextFactoryObject);
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}

How to mock a void method with Functional Interface/lambda param?

How do I mock a lambda expression that is passed as a param into a void method call?
I have the following class structure that I need to test, but I can't even instantiate it due to it's constructor.
Is there a way to mock the method call someManager.doSomething?
Or a way to mock item.isDoItemSave?
I can't figure it out and SomeClass.setDoSave throws a null pointer on the return call(SomeClass line 18) , since doSave is null.
Class I want to instantiate:
public SomeClass() {
private Boolean doSave;
private SomeManager someManager;
private SaveAction action;
public SomeClass(SomeManager someManager) {
this.someManager = someManager;
action = setDoSave() ? SAVE : null;
}
private boolean setDoSave() {
if(doSave == null) {
someManager.doSomething(item -> {
doSave = item.isDoItemSave();
});
}
return doSave;
}
}
SomeManager.doSomething is void:
public void doSomething(ItemUpdate update){
Item item = new Item();
update.update(item);
}
ItemUpdate is a functional interface:
#FunctionalInterface
public interface ItemUpdate {
void update(Item item);
}
I cannot refactor this constructor, who knows what will happen, the code is extremely coupled.
I just want to be able to instantiate SomeClass.
My test class looks like this, naturally tests fail in the #BeforeEach on SomeClass constructor call:
class SomeClassTest {
private SomeClass someClass;
#Mock
private SomeManager someManagerMock;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
this.someClass = new SomeClass(someManagerMock);
}
#Test
void someClassTest() {
someClass.anyOtherMethod();
}
}
A quick glance at the documentation shows the following example that I have applied to your situation
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
//configure the mock
// Java 8 - style 2 - assuming static import of AdditionalAnswers
doAnswer(answerVoid(ItemUpdate update) -> {
Item item = new Item();
//...populate item as needed
update.update(item);
})
.when(someManagerMock).doSomething(any(ItemUpdate.class));
this.someClass = new SomeClass(someManagerMock);
}
Reference Java 8 Custom Answer Support
Note that I have not tested this. I am going based on what was shown in the docs.
For now I have made changes so SomeClass at least instantiates.
Lesson learned, watch your assignments from Boolean to boolean.
private boolean setDoSave() {
if(doSave == null) {
someManager.doSomething(item -> {
doSave = item.isDoItemSave();
});
}
return doSave != null ? doSave : false;
}
I'm leaving this question open hoping someone with better knowledge of Mocking frameworks can provide a way of mocking this case.
I can't figure it out and SomeClass.setDoSave throws a null pointer,
since doSave is null.
SomeClass.setDoSave throws NPE since instance variable someManager is null.
Try adding #RunWith(MockitoJUnitRunner.class) to your test class.

Good practice to add protected methods for sake of unit testing?

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.

Junit test cases

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.

How to mock this in an Enum class using jmockt?

I am trying to write unit test for my below old legacy enum class. The method which I am trying to unit test is - toLocalPookString.
Whenever I am running my unit test code, it is always going inside the if statement in toLocalPookString method since this is always getting resolved to CORP.
public enum DatacenterEnum {
CORP, PHX, SLC, LVS;
private static final DatacenterEnum ourlocation = compareLocation();
private static DatacenterEnum compareLocation() {
// some code here
}
private String toLocalPookString() {
if (this == CORP || !(TestUtils.getEnvironmentName().equalsIgnoreCase("production"))) {
return "/pp/dc/phx";
}
return "/pp/dc/" + name().toLowerCase();
}
public static final String BETA_POOK_STRING = ourlocation.toLocalPookString();
}
Is there any way I can mock this to PHX or SLC or LVS apart from CORP so that in toLocalPookString it should not go inside if statement? I am using jmockit here.
new MockUp<TestUtils>() {
#Mock
public String getEnvironmentName() {
return "production";
}
};
String ss = DatacenterEnum.BETA_POOK_STRING;
System.out.println(ss);
It is pretty simple but somehow I am not able to understand how to do it? Any thoughts?
Well, you could easily mock the enum, as follows:
new MockUp<DatacenterEnum>() {
#Mock DatacenterEnum compareLocation() { return DatacenterEnum.LVS; }
};
However, because the JVM can only perform static initialization once for a given class/enum, the test would only work if the enum hadn't yet been loaded and initialized.
So, a more robust test would be the following.
#Test
public void whenDatacenterIsNotCORPThenLocalPookStringShouldIncludeEnumName() {
new MockUp<TestUtils>() {
#Mock String getEnvironmentName() { return "production"; }
};
DatacenterEnum notCORP = DatacenterEnum.LVS;
String ss = Deencapsulation.invoke(notCORP, "toLocalPookString");
assertTrue(ss.toUpperCase().endsWith(notCORP.name()));
}
This works, but note that writing separate tests for private methods is generally considered bad form. Ideally, tests should call public methods which would indirectly exercise the private ones. In this particular case, however, there is no such public method, so I guess it's acceptable.

Categories

Resources