Mocking an ArrayList using PwerMock - junit

i am trying to mock an arraylist as follows using Powermock
MockDao Class
PowerMockito.mockStatic(DailyReceiptsAndExceptionsDetailsDao.class);
PowerMockito.mockStatic(UtilityFunctions.class);
DailyReceiptsAndExceptionsExport dailyExceptionsExport = Mockito.mock(DailyReceiptsAndExceptionsExport.class);
List<DailyReceiptsAndExceptionsDetailsGridDto> resultList = getDailyExceptions(inputDto);
try{
PowerMockito.whenNew(DailyReceiptsAndExceptionsExport.class).withArguments(Mockito.any(DailyReceiptsAndExceptionsDetailsInputDto.class)).thenReturn(dailyExceptionsExport);
Mockito.when(DailyReceiptsAndExceptionsDetailsDao.getDailyReceiptsAndExceptions(Mockito.any(DailyReceiptsAndExceptionsDetailsInputDto.class))).thenReturn(resultList);
Mockito.when(UtilityFunctions.processReportSchedule(scheduleId, jobId,dailyExceptionsExport,(List<DailyReceiptsAndExceptionResultDTO>)Mockito.any(), null, null)).thenReturn(true);
}catch(Exception e){
}
I need to write tests for the following class.
public static Response getOutboundAvgCubeAndWeightUtilization(
#QueryParam("dc") String dc,
#QueryParam("asn") String asn,
#QueryParam("sortBy") String sort,
#QueryParam("isExport") boolean isExport,
#QueryParam("fileType") String fileType,
#QueryParam("scheduleId") BigDecimal scheduleId,
#QueryParam("jobId") BigDecimal jobId) {
ResponseDTO responseDto = new ResponseDTO();
DailyReceiptsAndExceptionsDetailsInputDto inputDto = new DailyReceiptsAndExceptionsDetailsInputDto ();
inputDto.setAsn(asn);
inputDto.setDc(dc);
inputDto.setSortBy(sort);
inputDto.setFileType(fileType);
inputDto.setExport(isExport);
String filePath = "";
try {
DailyReceiptsAndExceptionResultDTO resultDto = DailyReceiptsAndExceptionsDetailsBusinessManager.getInstance().manageDailyReceiptsAndExceptionsDetails(inputDto);
List<DailyReceiptsAndExceptionResultDTO> resultsList = new ArrayList<DailyReceiptsAndExceptionResultDTO>();
resultsList.add(resultDto);
if(scheduleId != null) {
boolean responseStatus = UtilityFunctions.processReportSchedule(scheduleId, jobId, new DailyReceiptsAndExceptionsExport(inputDto), resultsList, null,null);
responseDto.setResult(Boolean.toString(responseStatus));
return CommonUtil.convertResponseToJson(responseDto);
}
}
My tests class is as follows.
#Test
public void testGetOutboundAvgCubeAndWeightUtilization_4()
throws Exception {
String dc = "5854";
String asn = "*";
String sort = "SKU";
boolean isExport = false;
String fileType = "";
BigDecimal scheduleId = new BigDecimal(100);
BigDecimal jobId = new BigDecimal(100);
DailyReceiptsAndExceptionsDetailsInputDto inputDto = new DailyReceiptsAndExceptionsDetailsInputDto ();
inputDto.setAsn(asn);
inputDto.setDc(dc);
inputDto.setSortBy(sort);
inputDto.setFileType(fileType);
inputDto.setExport(isExport);
DailyReceiptsAndExceptionsDetailsMockDAO.mockgetDailyExceptions(inputDto, scheduleId, jobId);
Response result = DailyReceiptsAndExceptionsDetailsService.getOutboundAvgCubeAndWeightUtilization(dc, asn, sort, isExport, fileType, scheduleId, jobId);
String output = result.getEntity().toString();
assertEquals(true,output.contains("\"result\": \"true\""));
}
when iam running the test case, it was throwing error because, i think the mocking of the list is not correct.
Can anybody tell how to run this test scenario ....

Your mocks appear to be fine.
JUnit is failing the test because the line
assertEquals(true,output.contains("\"result\": \"true\""));
is failing: this means that your String output does not contain the text "result": "true"
Perhaps one way for you to figure out what is wrong is to either print out the value of output prior to the assertEquals() call or use a debugger to see what the value of output is.
As a side note, assertEquals(true, <condition>) is very verbose, you can use assertTrue(<condition>) instead.

According to your comment the test is simply failing. (AssertionErrors are JUnit's way of saying that your test failed.)
You could get a better error message if you use Hamcrest. Therefore you have to change the last two lines of your code:
assertThat(result.getEntity(), hasToString(containsString("\"result\": \"true\"")));
Add some static imports for org.hamcrest.MatcherAssert.assertThat and org.hamcrest.Matchers.*.
The new error message may help you finding the error.

Related

Mocking a mongo find query and java into method

I have following query in the method:
public String getWrapperAttribute(String id, int counter) {
List<ResWrapper> wrapperList = new ArrayList<>();
String key = "Test";
String id = "Test";
objcollection.find(eq(key, id)).comment("Running the first query").into(wrapperList);
if (wrapperList.size() > 0) {
ResWrapper wrapperObj = wrapperList.get(0);
return wrapperObj .getField().getAttribute();
}
I want to unit test the method and want to mock the find query but keep getting NPE.
My unit test method:
#InjectMocks
Reader reader;
#Mock
MongoCollection<ResWrapper>objcollection;
#Mock
FindIterable<ResWrapper> findIterable;
#Test
public void getWrapperAttribute_Test() {
MongoCursor cursor = mock(MongoCursor.class);
ArrayList<ResWrapper> wrapperList = new ArrayList<>();
ResWrapper resWrapper = new ResWrapper();
Res res = new Res();
Res.setAttribute("1234545");
ResWrapper.setField(res);
WrapperList.add(ResWrapper);
Bson filter1 = eq("Test","Test");
when(objcollection.find(filter1)).thenReturn(findIterable);
when(findIterable.into(new ArrayList<>())).thenReturn(WrapperList)
reader.getWrapperAttribute("Test", 1);
}
I keep getting there is no find(Bson) for the type reader.
Is there anyway around this, this is existing code, just writing junit test case for it.

jackson reading in non-existent and null values to “” and marshalling out “” to non-existent values?

I read through this post Jackson: deserializing null Strings as empty Strings which has this cool trick
mapper.configOverride(String.class)
.setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
THEN on the flipside, I read through this post Jackson serialization: ignore empty values (or null) which has this cool trick
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
This is VERY VERY close except I really don't want incoming data to be null in any case. I have the following code printing 4 situations with the above settings BUT want to fix the null piece so any json we unmarshal into java results in
public class MapperTest {
private static final Logger log = LoggerFactory.getLogger(MapperTest.class);
private ObjectMapper mapper = new ObjectMapper();
public MapperTest() {
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configOverride(String.class)
.setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
}
public static void main(String[] args) throws JsonProcessingException {
new MapperTest().start();
}
private void start() throws JsonProcessingException {
//write out java color=null resulting in NO field...
String val = mapper.writeValueAsString(new Something());
log.info("val="+val);
Something something = mapper.readValue(val, Something.class);
log.info("value='"+something.getColor()+"'");
//write out java color="" resulting in NO field...
Something s = new Something();
s.setColor("");
String val2 = mapper.writeValueAsString(new Something());
log.info("val="+val2);
String temp = "{\"color\":null,\"something\":0}";
Something something2 = mapper.readValue(temp, Something.class);
log.info("value2='"+something2.getColor()+"'");
}
}
The output is then
INFO: val={"something":0}
INFO: value='null'
INFO: val={"something":0}
INFO: value2=''
NOTE: The value = 'null' is NOT what I desire and want that to also be empty string. Notice that if customers give a color:'null', it does result in empty string. Non-existence should result in the same thing for us "".
This is a HUGE win in less mistakes in this area 'for us' I mean.
thanks,
Dean

Spring - Return Raw JSON without double serialization

I know there are other posts similar to this, but I haven't found any that help me find a solution for this particular case.
I am trying to return a HashMap<String, Object> from my Controller.
The Object part is a JSON string, but its being double serialized and not returned as a raw JSON string, thus not ending up with extra quotations and escape characters.
Controller function:
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public HashMap<String, Object> heartbeat(){
String streamInfo = service.getStreamInfo();
String streamCursorInfo = service.getStreamCursorInfo();
String topicInfo = service.getTopicInfo();
String greeting = "This is a sample app for using Spring Boot with MapR Streams.";
HashMap<String, Object> results = new HashMap();
results.put("greeting", greeting);
results.put("streamInfo", streamInfo);
results.put("streamCursorInfo", streamCursorInfo);
results.put("topicInfo", topicInfo);
return results;
}
Service function:
private String performCURL(String[] command){
StringBuilder stringBuilder = new StringBuilder();
try{
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process p = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while((line = reader.readLine()) != null){
stringBuilder.append(line);
}
}
catch(Exception e){
LOGGER.error(ExceptionUtils.getRootCauseMessage(e));
}
return stringBuilder.toString();
}
The cURL command I run already returns a raw JSON string. So im just trying to add it to the HashMap to be returned in the heartbeat response.
But every time I run this, my output looks like:
{
"greeting": "This is a sample app for using Spring Boot with MapR Streams.",
"streamCursorInfo": "{\"timestamp\":1538676344564,\"timeofday\":\"2018-10-04 02:05:44.564 GMT-0400 PM\",\"status\":\"OK\",\"total\":1,\"data\":[{\"consumergroup\":\"MapRDBConsumerGroup\",\"topic\":\"weightTags\",\"partitionid\":\"0\",\"produceroffset\":\"44707\",\"committedoffset\":\"10001\",\"producertimestamp\":\"2018-10-03T05:57:27.128-0400 PM\",\"consumertimestamp\":\"2018-09-21T12:35:51.654-0400 PM\",\"consumerlagmillis\":\"1056095474\"}]}",
...
}
If i return only the single string, such as streamInfo then it works fine and doesnt add the extra quotes and escape chars.
Can anyone explain what im missing or need to do to prevent this double serialization?
Instead of returning a HashMap, create an object like this:
public class HeartbeatResult {
private String greeting;
... //other fields here
#JsonRawValue
private String streamCursorInfo;
... //getters and setters here (or make the object immutable by having just a constructor and getters)
}
With #JsonRawValue Jackson will serialize the string as is. See https://www.baeldung.com/jackson-annotations for more info.
streamCursorInfo is a string, not an object => the serialization will escape the " character.
If you are able to return the object containing the data, it will work out of the box. If what you have is just a String, I suggest to serialize it to JsonNode and add it in your response
ObjectMapper objectMapper = new ObjectMapper();
JsonNode streamCursorInfo = objectMapper.readTree(service.getStreamInfo())
results.put("streamCursorInfo", streamCursorInfo);

Can't read Mocked Java.io.Reader

I want to test following code with Mockito:
public static String funcToTest(String query) throws Exception {
String url = Config.getURL(serviceName);
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
String resultantString= "";
method.setQueryString(URIUtil.encodeQuery(query));
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
Reader reader = new InputStreamReader(method
.getResponseBodyAsStream());
int charValue = 0;
StringBuffer sb = new StringBuffer(1024);
while ((charValue = reader.read()) != -1) {
sb.append((char) charValue);
}
resultantString = sb.toString();
}
method.releaseConnection();
return resultantString;
}
I created the test like following:
#Test
public void testFunc() throws Exception{
HttpMethod method = Mockito.mock(HttpMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
Reader reader = Mockito.mock(Reader.class);
when(method.getResponseBodyAsStream()).thenReturn(inputStream);
PowerMockito.whenNew(Reader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int)'1', -1);
String actualResult = cls.funcToTest("");
String expected = "1";
assertEquals(expected, actualResult);
}
But the reader.read() method is not returning 1. Instead it always returns -1. How should I mock Reader so that read() method will return something else other than -1.
Thanks.
First of all , your test code is doing lots of .class mocking to mock function local variables / references. Mocking is for class dependencies and not for function local variables.
As written, you can't test your function funcToTest with mocking alone. You need to rewrite this function if not willing to use real objects for - HttpMethod & Reader.
You need to remove object creation code with new outside this function if you wish to mock calls on those objects and replace code of new with this get method. e.g.
protected HttpMethod getHttpMethod(String Url){
return new GetMethod(url);
}
Also, I don't see you mocking this line for a fake URL - it seems necessary for unit testing.
String url = Config.getURL(serviceName);
After taking object creation code outside your function, you need to create a new class than extends your SUT ( Subject Under Test ) and you override these methods ( getHttpMethod) to provide fake/mocked instances.
You need to write similar method to get Reader instance.
Then you test this new class - extended from your SUT since object creation logic need not to be tested.
Without taking object creation code outside the function, I don't see a way of mocking it by mockito.
Hope it helps !!
It must work, I'm sorry what make you slightly confused )
// annotations is very important, cls I your tested class name, i assume cls is yours
#RunWith(PowerMockRunner.class)
#PrepareForTest({cls.class})
public class PrinterTest {
#Test
public void print() throws Exception {
String url = "";
GetMethod method = Mockito.mock(GetMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
InputStreamReader reader = Mockito.mock(InputStreamReader.class);
Mockito.when(method.getResponseBodyAsStream()).thenReturn(inputStream);
//forgot about it )
PowerMockito.whenNew(GetMethod.class).withArguments(eq(url)).thenReturn(method);
PowerMockito.whenNew(InputStreamReader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int) '1', -1);
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
String actualResult = cls.funcToTest(url);
String expected = "1";
assertEquals(expected, actualResult);
}
}

How to deserialize Jackson Json NULL String to Date with JsonFormat

I have looked a lot but still couldn't get the answer so far, any help is really appreciated!
I have a simple String to Date field mapping and try to read a JSON string to Java object.
#JsonInclude(value=Include.NON_EMPTY)
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="dd-MMM-yyyy", timezone="PST")
protected Date eolAnnounceDate;
However I am getting the following exception if the JSON string value is empty.
Can you someone tell me how to get around this? I have tried a few options but they are all for serialization.
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
Exception :
java.lang.IllegalArgumentException: Failed to parse Date value 'NULL' (format: "dd-MMM-yyyy"): Unparseable date: "NULL"
com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateBasedDeserializer._parseDate(DateDeserializers.java:180)
com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:279)
com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:260)
com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:464)
com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:295)
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:230)
com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:207)
com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23)
com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:464)
com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:295)
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
com.cisco.cre.dao.impl.ElasticsearchDAOImpl.getListByIdsFilter(ElasticsearchDAOImpl.java:94)
Thanks
- Atul
Your problem is not that a null value is passed in the JSON. The problem is that the JSON contains a string that has the value "NULL".
So, in order to fix this there are a number of available approaches. I think that the following two will work for this case.
Alternative 1: Fix the JSON
The first alternative is to fix the JSON so that it does not contain the the string value "NULL" and instead contain the value null (not quoted) or simply skip it.
Imagine the following POJO:
public class DatePojo {
#JsonInclude(value= JsonInclude.Include.NON_EMPTY)
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="dd-MMM-yyyy", timezone="PST")
#JsonProperty("date")
private Date date;
}
The following test shows that valid dates, empty values and null values work:
#Test
public void testJson() throws IOException {
String jsonWithValidDate = "{\"date\":\"12-Jun-1982\"}";
String jsonWithNoDate = "{}";
String jsonWithNullDate = "{\"date\":null}";
ObjectMapper mapper = new ObjectMapper();
final DatePojo pojoWithValidDate = mapper.readValue(jsonWithValidDate, DatePojo.class);
final DatePojo pojoWithNoDate = mapper.readValue(jsonWithNoDate, DatePojo.class);
final DatePojo pojoWithNullDate = mapper.readValue(jsonWithNullDate, DatePojo.class);
Assert.assertNotNull(pojoWithValidDate.date);
Assert.assertNull(pojoWithNoDate.date);
Assert.assertNull(pojoWithNullDate.date);
}
However, if you pass along the value "NULL" the test fails since "NULL" can not be parsed as a date:
#Test(expected = JsonMappingException.class)
public void testInvalidJson() throws IOException {
String jsonWithNullString = "{\"date\":\"NULL\"}";
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(jsonWithNullString, DatePojo.class); // Throws the exception
Assert.fail();
}
Alternative 2: provide your own converter that handles "NULL"
If it is not possible to fix the JSON (as described in alternative 1) you can provide your own converter.
Setup your pojo like this instead:
public class DatePojo {
#JsonProperty("date")
#JsonDeserialize(converter = MyDateConverter.class)
private Date date;
}
And provide a converter along the lines of:
public class MyDateConverter extends StdConverter<String, Date> {
#Override
public Date convert(final String value) {
if (value == null || value.equals("NULL")) {
return null;
}
try {
return new SimpleDateFormat("dd-MMM-yyyy").parse(value);
} catch (ParseException e) {
throw new IllegalStateException("Unable to parse date", e);
}
}
}
Then, you should be all set. The following test passes:
#Test
public void testJson() throws IOException {
String jsonWithValidDate = "{\"date\":\"12-Jun-1982\"}";
String jsonWithNoDate = "{}";
String jsonWithNullDate = "{\"date\":null}";
String jsonWithNullString = "{\"date\":\"NULL\"}"; // "NULL"
ObjectMapper mapper = new ObjectMapper();
final DatePojo pojoWithValidDate = mapper.readValue(jsonWithValidDate, DatePojo.class);
final DatePojo pojoWithNoDate = mapper.readValue(jsonWithNoDate, DatePojo.class);
final DatePojo pojoWithNullDate = mapper.readValue(jsonWithNullDate, DatePojo.class);
final DatePojo pojoWithNullStr = mapper.readValue(jsonWithNullString, DatePojo.class); // Works
Assert.assertNotNull(pojoWithValidDate.date);
Assert.assertNull(pojoWithNoDate.date);
Assert.assertNull(pojoWithNullDate.date);
Assert.assertNull(pojoWithNullStr.date); // Works
}
IMO, the best approach is to use alternative 1 where you simply change the JSON.