Mockito when method call not invoked, Verify return message "Wanted but not invoked,Actually, there were zero interactions with this mock" - mockito

I am new to Mockito.
I have a problem.
I am trying to mock a class and call a method of that class with a hashmap which returns the same hashmap modified.
But i see that mocked method is not invoked. If i did verify i got the message as "Wanted but not invoked,Actually, there were zero interactions with this mock"
Here is my code
Class to test
public class ClassA{
private ClassB bb = new ClassB();
public boolean init() {
bb= new ClassB();
bb.init();
return true;
}
public void methodToTest(){
Map<String, Map<String, Integer>> hashmap= new LinkedHashMap<>();
hashmap = bb.method1(hashmap);
}
public ClassB getBB() {
return bb;
}
public void setBB(ClassB bb) {
this.bb= bb;
}
}
My Test class
#RunWith(PowerMockRunner.class)
public class TestClassA {
#Test
#PrepareForTest({Utilities.class, Logger.class, LoggerFactory.class})
public void getData() throws JsonProcessingException, JSONException {
Map<String, Map<String, Integer>> hashmap= new LinkedHashMap<>();
Map<String, Map<String, Integer>> newHashmap= new LinkedHashMap<>();
ClassA class2Test= new ClassA ();
ClassB mockClassB= Mockito.mock(ClassB.class);
PowerMockito.whenNew(ClassB.class).withAnyArguments().thenReturn(mockClassB);
Mockito.when(mockClassB.method1(hashmap)).thenReturn(newHashmap);
Mockito.verify(mockClassB).method1(hashmap);
class2Test.methodToTest();
}
}

I think you mixed a few things together.
With the refactored version you need to inject the mock for ClassB into ClassA (no need to use PowerMockito.whenNew).
Also note that the verifiy call has to be after the test method invocation.
#RunWith(PowerMockRunner.class)
public class SampleTest {
static class ClassB {
public Map<String, Map<String, Integer>> method1(Map<String, Map<String, Integer>> hashmap) {
return null;
}
}
static class ClassA {
private ClassB bb = new ClassB();
public void methodToTest() {
Map<String, Map<String, Integer>> hashmap = new LinkedHashMap<>();
hashmap = bb.method1(hashmap);
}
}
#Mock
ClassB bb;
#InjectMocks
ClassA class2Test;
#Test
public void test() throws Exception {
Map<String, Map<String, Integer>> hashmap = new LinkedHashMap<>();
Map<String, Map<String, Integer>> newHashmap = new LinkedHashMap<>();
Mockito.when(bb.method1(hashmap)).thenReturn(newHashmap);
class2Test.methodToTest();
Mockito.verify(bb).method1(hashmap);
}
}
For your old code the test would look something like this, but if you can use the version above.
The #PrepareForTest has to contain the class where the byte code should be manipulated, in this case ClassA.
#Test
#PrepareForTest(ClassA.class)
public void test() throws Exception {
Map<String, Map<String, Integer>> hashmap = new LinkedHashMap<>();
Map<String, Map<String, Integer>> newHashmap = new LinkedHashMap<>();
ClassB bb = Mockito.mock(ClassB.class);
Mockito.when(bb.method1(hashmap)).thenReturn(newHashmap);
PowerMockito.whenNew(ClassB.class).withAnyArguments().thenReturn(bb);
ClassA class2Test = new ClassA();
class2Test.methodToTest();
Mockito.verify(bb).method1(hashmap);
}

Related

Springboot mockito mock a field

I want to mock the TreeMap in Service class, I tried to mock using TreeMap<String, String> requestsMap = Mockito.mock(TreeMap.class); But the map is getting null at runtime.
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class ServiceTest {
#InjectMocks
private Service service;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
TreeMap<String, String> requestsMap = Mockito.mock(TreeMap.class);
}
}
#Service
public class Service {
private TreeMap<String, String> requestsMap = null;
}
Your Service class doesn't actually do anything but declare and initialize the requestMap to null. Also, your test method doesn't do anything other than declare a mock requestMap.
In addition to the code you have, write a method in the Service that uses the request map and just declare/autowire the requestMap. In your test, use the #Mock annotation on a declaration of your mock requestMap. Finally, use the mocked requestMap in your test.
For example:
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class ServiceTest {
#Mock
TreeMap<String, String> requestsMap;
#InjectMocks
private Service service;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
when(requestMap.get("foo")).thenReturn("bar");
String result = service.doSomething();
assertEquals(result, "bar");
}
}
#Service
public class Service {
#Autowired
private TreeMap<String, String> requestsMap;
public String doSomething() {
return requestMap.get("foo");
}
}

Method inside "When" actually being called

When I am testing a class A (TestNG) which uses some methods from some other class Helper Class
I am mocking the helper class(Mockito) for testing class A.
but when(helper.methodUsedByClassA(value)).thenReturn(new HashMap>())
this line of code is actually calling helper.methodUsedByClassA and a null pointer exception is thrown (because of data I am using for testing is not valid)
why is this happening? Why would the method name inside mockito "when" actually be called ?
class ATest{
#Mock
private Helper helper;
private A target;
#BeforeTest
public void setUp() {
MockitoAnnotations.initMocks(this);
this.target = new UpdateDigicatKdpAsinUtil(helper);
}
#Test(dataProvider = "data")
public void testMethod(List<String> value) {
when(helper.methodUsedByClassA(value)).thenReturn(new HashMap<String, List<String>>({{put("test", new ArrayList<>())}}));
}
#DataProvider
public Object[][] data(){
List<String> list = new ArrayList<>();
return new Object[][]
{
{list}
}
}
class Helper{
public Map<String, List<String>> methoUsedByClassA(int value) {
//This method is being executed because it is mentioned inside "when"
}
}
I guess you get an NPE because helper is NULL.
The problem is that the #Mock annotation isn't processed and because of that, the variable helper isn't initialized.
You have to annotate the test class with #RunWith(MockitoJUnitRunner.class). MockitoJUnitRunner will process the #Mock annotation and create the mock.

Is this code thread safe with spring PostConstruct

I have done some tests on these two classes. Could someone please help to determine if these two classes are threadsafe? Could someone help to identify if not using concurrentHashMap, but use HashMap would it cause any concurrent issue. How can I make it more threadsafe? What is the best approach to testing it with concurrent testing?
I tested it with Hashmap only and it works fine. However, my scale of test is around 20 req/s for 2 mins.
Can anyone suggest if I should increase the req rate and try again or can point somewhere that must require fix.
#Component
public class TestLonggersImpl
implements TestSLongger {
#Autowired
YamlReader yamlReader;
#Autowired
TestSCatalog gSCatalog;
#Autowired
ApplicationContext applicationContext;
private static HashMap<String, TestLonggerImpl> gImplHashMap = new HashMap<>();
private static final Longger LONGER = LonggerFactory.getLongger(AbstractSLongger.class);
#PostConstruct
public void init() {
final String[] sts = yamlReader.getTestStreamNames();
for (String st : sts) {
System.out.println(st);
LONGER.info(st);
}
HashMap<String, BSCatalog> statsCatalogHashMap = gSCatalog.getCatalogHashMap();
for (Map.Entry<String, BSCatalog> entry : statsCatalogHashMap.entrySet()) {
BSCatalog bCatalog = statsCatalogHashMap.get(entry.getKey());
//Issue on creating the basicCategory
SProperties sProperties = yamlReader.getTestMap().get(entry.getKey());
Category category = new BasicCategory(sProperties.getSDefinitions(),
bCatalog.getVersion(),
bCatalog.getDescription(), new HashSet<>());
final int version = statsCatalogHashMap.get(entry.getKey()).getVersion();
getTestImplHashMap().put(entry.getKey(),
applicationContext.getBean(TestLonggerImpl.class, category,
entry.getKey(),
version));
}
}
#Override
public void logMessage(String st, String message) {
if (getTestImplHashMap() != null && getTestImplHashMap().get(st) != null) {
getTestImplHashMap().get(st).log(message);
}
}
#VisibleForTesting
static HashMap<String, TestLonggerImpl> getTestImplHashMap() {
return gImplHashMap;
}
}
*** 2nd class
#Component
public class GStatsCatalog {
#Autowired
YamlReader yamlReader;
private static HashMap<String, BStatsCatalog> stCatalogHashMap = new HashMap<>();
#PostConstruct
public void init() {
String[] streams = yamlReader.getGSNames();
for (String stream : streams) {
BStatsCatalog bCatalog = new BStatsCatalog();
SProperties streamProperties = yamlReader.getGMap().get(stream);
bCatalog.setSName(stream);
int version = VERSION;
try {
version = Integer.parseInt(streamProperties.getVersion());
} catch (Exception e) {
System.out.println(e.getMessage());
}
bCatalog.setVersion(version);
bCatalog.setDescription(streamProperties.getDescription());
stCatalogHashMap.put(stream, bCatalog);
}
}
public static HashMap<String, BStatsCatalog> getCatalogHashMap() {
return stCatalogHashMap;
}
public void setYamlReader(YamlReader yamlReader) {
this.yamlReader = yamlReader;
}
}
I think the methods under #postconstruct are threadsafe. It only runs once after the bean created in the whole lifecircle of the bean.

HashMap is empty after deserialization with Jersey and Jackson

I have a REST web service using Jersey 1.17.1 and Jackson 1.9.2.
The API looks like this:
public class PlayerRequest {
private String language;
private String playerId;
private Map<String, String> params;
}
When this service is called by other component, the params map is received empty:
PlayerRequest [language=null, playerId=100036343, params={}]
Original request from other component:
PlayerRequest [language=null, playerId=100036343, params={context=mobile, countrycode=SE, partnerskin=8, locale=en_GB, ipaddress=62.209.186.13}]
Why is the HashMap empty after the deserialization?
In your PlayerRequest class, create a method annotated with #JsonAnySetter, as following:
#JsonAnySetter
public void set(String key, String value) {
params.put(key, value);
}
This method works as a fallback handler for all unrecognized properties found in the JSON content.
To use the above mentioned approach, ensure the params field is being initialized:
private Map<String, String> params = new HashMap<String, String>();
So, your PlayerRequest class would be like:
public class PlayerRequest {
private String language;
private String playerId;
private Map<String, String> params = new HashMap<String, String>();
public PlayerRequest() { }
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getPlayerId() {
return playerId;
}
public void setPlayerId(String playerId) {
this.playerId = playerId;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
#JsonAnySetter
public void set(String key, String value) {
params.put(key, value);
}
}
Fixed by implementing and adaptor(javax.xml.bind.annotation.adapters.XmlAdapter) and annotated the map in api with #XmlJavaTypeAdapter

#XmlPath(".") conflicts with #XmlAdapter

having this Jaxb Xml definition, i try to remove the Map Elements Wrapper by adding #XmlPath(".") but it cause exception during the unmarchaling
#XmlRootElement
public abstract class ViewElement{
#XmlJavaTypeAdapter(value=EventAdapter.class)
public Map<Event, String> getEvents() {
}
private transient Class entityType;
public Class getEntityType() {
return entityType;
}
}
And the EventAdapter is
public class EventAdapter extends XmlAdapter<EventAdapter.AdaptedMap, Map<Event, String>> {
public static class AdaptedMap {
#XmlVariableNode("key")
List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();
}
public static class AdaptedEntry {
#XmlTransient
public String key;
#XmlValue
public String value;
}
.....
}
my output was
<element>
<events>
<onCellEdit>do some thing<onCellEdit>
</events>
<entityType>com.agitech.erp.model.erp.ErpFolder</entityType>
<element>
I try to remove the <events> tag by adding #XmlPath(".")
#XmlPath(".")
#XmlJavaTypeAdapter(value=EventAdapter.class)
public Map<Event, String> getEvents() {
}
The output is good
<element>
<onCellEdit>do some thing<onCellEdit>
<entityType>com.agitech.erp.model.erp.ErpFolder</entityType>
<element>
but the unmarchaling faileds
Caused by: Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[entityType-->view.entityType/text()]] with descriptor [XMLDescriptor(com.agitech.erp.view.BeanView --> [DatabaseTable(view), DatabaseTable(viewFrame), DatabaseTable(viewElement)])], could not be converted to [class java.lang.Class].
Internal Exception: java.lang.ClassNotFoundException:
at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConvertedToClass(ConversionException.java:95)
at org.eclipse.persistence.internal.helper.ConversionManager.convertObjectToClass(ConversionManager.java:446)
Debuging Jaxb bring me to the line
org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue
public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) {
...
line 205 unmarshalRecord.setAttributeValue(convertedValue, xmlDirectMapping);
}
During the unmarchaling of entityType value, the UnmarshalRecordImpl.currentObj contains the EventAdapter instead of the parent element
I modify org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl
public XPathNode getNonAttributeXPathNode(String namespaceURI, String localName, String qName, Attributes attributes) {
....
if(null == resultNode && null == nonPredicateNode) {
// ANY MAPPING
resultNode = xPathNode.getAnyNode();
// by default it return the EventAdapter, changing it to NULL fix my problem
}
....
}
Not a safe solution
I have been able to reproduce the issue that you are seeing, but haven't yet worked out the cause. You can use the following bug to track the progress on this issue:
http://bugs.eclipse.org/457169
After trying a lot of things, I was able to find a workaround for this issue. I thought of posting here the same so it can be helpful to someone else in the future. The lead has confirmed the issue around 5 years ago but seems like they have not fixed it and I was facing a similar issue.
Basically, we can use the beforeMarshal and afterUnmarshal methods to change the values in the fields.
You need to create a field List<Object> with #XmlAnyElement(lax=true) along with Map<String,Object>.
Remove the #XmlPath(".") and the XMLAdapter class.
Mark the field Map<String, Object> with #XmlTransient.
Now within the beforeMarshal and afterMarshal fields, you can exchange the data. During the unmarshal in beforeunmarshal, all the unknown field values will be present within the List<Object> loop over it and add it to the Map<String, Object>.
Similarly during the marshaling, you can move the values Map<String, Object> to List<Object> by creating the DOM elements.
Marshaling all values are added to root as DOM Elements are present and during Unmarshaling known values are read first and then-unknown values are stored within List<Object> due to #XmlAnyElement.
I have created an example using the Customer class, you can modify it accordingly for your need.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
#JsonInclude(Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#XmlRootElement(name = "Customer")
#XmlType(name = "Customer", propOrder = {"name", "age", "otherElements"})
#XmlAccessorType(XmlAccessType.FIELD)
#Getter
#Setter
#AllArgsConstructor
#ToString
#NoArgsConstructor
public class Customer {
#XmlTransient
private String isA;
private String name;
private String age;
#XmlAnyElement(lax = true)
#JsonIgnore
private List<Object> otherElements = new ArrayList<>();
#JsonIgnore
#XmlTransient
private Map<String, Object> userExtensions = new HashMap<>();
#JsonAnyGetter
#JsonSerialize(using = CustomExtensionsSerializer.class)
public Map<String, Object> getUserExtensions() {
return userExtensions;
}
#JsonAnySetter
public void setUserExtensions(String key, Object value) {
userExtensions.put(key, value);
}
private void beforeMarshal(Marshaller m) throws ParserConfigurationException {
System.out.println("Before Marshalling User Extension: " + userExtensions);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
otherElements = extensionsModifier.Marshalling(userExtensions);
System.out.println("Before Marshalling Final Other Elements " + otherElements);
userExtensions = new HashMap<>();
}
private void afterUnmarshal(Unmarshaller m, Object parent) throws ParserConfigurationException {
System.out.println("After Unmarshalling : " + otherElements);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
userExtensions = extensionsModifier.Unmarshalling(otherElements);
otherElements = new ArrayList();
}
}
You can refer the creation of DOM ELEMENTS here:https://stackoverflow.com/a/24239105/7584240
You can refer my complete answer here: https://stackoverflow.com/a/67923216/7584240

Resources