How to use argument captor for unit test RestTemplate java - junit

private static final MediaType MULTIPART_FORM_DATA_BOUNDARY = MediaType.valueOf("multipart/form-data;boundary=BOUNDARY");
#Qualifier(REST_TEMPLATE)
private final RestTemplate restTemplate;
private final PojoToMultiValueMapMapper mapper;
private final ClientProperties properties;
public void archivePojo(final Pojo pojo) {
restTemplate.postForEntity(properties.getUrl(), buildHttpEntity(pojo), Void.class);
}
private HttpEntity<?> buildHttpEntity(final Pojo pojo) {
HttpHeaders headers = new HttpHeaders();
headers.add(X_REQUESTING_SYSTEM_KEY, X_REQUESTING_SYSTEM_VALUE);
headers.setContentType(MULTIPART_FORM_DATA_BOUNDARY);
return new HttpEntity<>(mapper.map(pojo), headers);
}
How to mock the rest template?

#Mock
private RestTemplate restTemplate;
#Captor
private ArgumentCaptor<String> urlCaptor;
#Mock
private PojoToMultiValueMapMapper mapper;
#Captor
private ArgumentCaptor<HttpEntity> headersCaptor;
private static final String HEADER_REQUESTING_SYSTEM_KEY = "x-requesting-system";
private static final String EXPECTED_CONTENT_TYPE_VALUE = "multipart/form-data;boundary=BOUNDARY";
#Test
void testHeaderIsPopulated() {
pojoRestClient.archivePojo(Pojo.builder().build());
verify(restTemplate).postForEntity(urlCaptor.capture(), headersCaptor.capture(), any());
assertNotNull(headersCaptor.getValue());
assertNotNull(headersCaptor.getValue()
.getHeaders()
.get(HEADER_REQUESTING_SYSTEM_KEY));
assertThat(headersCaptor.getValue()
.getHeaders()
.getContentType()
.toString()).hasToString(EXPECTED_CONTENT_TYPE_VALUE);
}

Related

How to test custom Object via #JsonTest in Spring?

I have my DeskDTO class that I have to test (guess I should). I found this toutorial: https://dzone.com/articles/testing-data-transfer-object-and-rest-controllers on internet but there is no explanation how to test custom class which my main class contains. To be clear:
My DeskDTO:
public class DeskDTO {
private Long deskId;
private String deskNumber;
private String additionalNote;
private LocalizationDTO localization;
private Set<ElectronicEquipmentDTO> electronicEquipments;
My test class:
#SpringBootTest(classes = ReliceApplication.class)
#RunWith(SpringRunner.class)
public class DeskDTOTest {
private JacksonTester<DeskDTO> jacksonTester;
private static final String DESK_NUMBER = "4-124";
private static final String ADDITIONAL_NOTE = "Very good desk";
private static LocalizationDTO localization;
private static Set<ElectronicEquipmentDTO> electronicEquipments;
private DeskDTO deskDTO;
#Before
public void setup() throws ParseException { //yes I know Im noob, Im still learning
ObjectMapper objectMapper = new ObjectMapper();
JacksonTester.initFields(this, objectMapper);
BuildingDTO buildingDTO = new BuildingDTO();
buildingDTO.setNameOfBuilding("Building D");
FloorDTO floorDTO = new FloorDTO();
floorDTO.setFloorNumber(4);
floorDTO.setBuilding(buildingDTO);
localization = new LocalizationDTO();
localization.setFloor(floorDTO);
localization.setxAxis(5);
localization.setyAxis(6);
ElectronicEquipmentDTO electronicEquipment = new ElectronicEquipmentDTO();
electronicEquipment.setAdditionalNote("Nice laptop");
electronicEquipment.setType(ElectronicEquipmentType.PC);
electronicEquipment.setClient("Lufthansa");
electronicEquipment.setExternalId("WS-1234");
electronicEquipment.setLocalization(localization);
electronicEquipments = new HashSet<>();
electronicEquipments.add(electronicEquipment);
deskDTO = new DeskDTO(DESK_NUMBER, ADDITIONAL_NOTE, localization, electronicEquipments);
}
private <T> T asParsedJson(Object object) throws JsonProcessingException {
String json = new ObjectMapper().writeValueAsString(object);
return JsonPath.read(json, "$");
}
#Test //this is working
public void setDeskNumberSerializes() throws IOException {
assertThat(this.jacksonTester.write(deskDTO))
.extractingJsonPathStringValue("#.deskNumber")
.isEqualTo(DESK_NUMBER);
}
#Test //same
public void setAdditionalNoteSerializes() throws IOException {
assertThat(this.jacksonTester.write(deskDTO))
.extractingJsonPathStringValue("#.additionalNote")
.isEqualTo(ADDITIONAL_NOTE);
}
#Test //this does not work
public void setLocalizationSerializes() throws IOException {
assertThat(this.jacksonTester.write(deskDTO))
.extractingJsonPathStringValue("#.localization")
.isEqualTo(localization);
}
#Test //this set does not work either
public void setElectronicEquipmentsSerializes() throws IOException {
assertThat(this.jacksonTester.write(deskDTO))
.extractingJsonPathArrayValue("#.electronicEquipments")
.isEqualTo(electronicEquipments);
}
}
When I am using .extractingJsonPathStringValue I've got:
java.lang.AssertionError: Expected a string at JSON path "#.localization" but found: {floor={floorId=null, floorNumber=4, building={buildingId=null, nameOfBuilding=Building D}}, xAxis=5, yAxis=6}
and when I am using .extractingJsonPathMapValue I've got:
org.opentest4j.AssertionFailedError:
Expecting:
<{"floor"={"building"={"buildingId"=null, "nameOfBuilding"="Building D"}, "floorId"=null, "floorNumber"=4}, "xAxis"=5, "yAxis"=6}>
to be equal to:
<com.mrfisherman.relice.Dto.LocalizationDTO#2aafa84f>
but was not.
Expected :com.mrfisherman.relice.Dto.LocalizationDTO#2aafa84f
Actual :{floor={floorId=null, floorNumber=4, building={buildingId=null, nameOfBuilding=Building D}}, xAxis=5, yAxis=6}

How to make #JsonView annotated Rest apis serializes all fields

I have a rest api like "/users/{userId}"
This api returns User data but filters out password by #JsonView(ResourceView.Public.class) annotation.
But I want to get password when the unit test runs.
Is there a way to igore #JsonView annotation when test is running.
Or any other options for me?
public class ResourceView {
public interface Public {}
public interface Friends extends Public {}
public interface Family extends Friends {}
}
public class User {
#JsonView(ResourceView.Public.class)
private String name;
#JsonView(ResourceView.Family.class)
private String password;
}
#RestController
public class UserController {
#Autowired
private UserService userService;
#JsonView(ResourceView.Public.class)
#GetMapping(value = "/users/{userId}")
public User getUser(#PathVariable("userId") String userId) {
return userService.getUser(userId);
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)
#ActiveProfiles(profiles = "test")
public class UserServiceTest {
#Autowired
protected TestRestTemplate restTemplate;
#Value("${local.server.port}")
private int port;
protected String apiEndpoint;
#Before
protected void setUp() {
initRequestContext();
apiEndpoint = "http://localhost:" + port;
}
protected ResponseEntity<User> requestGetUser(String userId) {
ResponseEntity<User> res = restTemplate.exchange(
apiEndpoint + "/users/" + userId,
HttpMethod.GET,
new HttpEntity<>("parameters", createDefaultHttpHeaders()),
new ParameterizedTypeReference<User>() {});
return res;
}
#Test
public void testGetUser() throws Exception {
ResponseEntity<User> apiRes = requestGetUsers(request);
assertThat(apiRes.getStatusCode(), is(HttpStatus.OK));
User user = apiRes.getBody();
assertThat(user.getName(), is(notNullValue()));
assertThat(user.getPassword(), is(notNullValue()));
}
}
#Configuration
public class MyConfig {
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper().configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
return objectMapper;
}
}

How to deserialize JSON to complex POJO<> with List of Generic Objects

I use jackson-databind 2.8.0
I have object with Generic Data
public class JsonItem<T> implements Serializable {
private static final long serialVersionUID = -8435937749132073097L;
#JsonProperty(required = true)
private boolean success;
#JsonProperty(required = false)
private T data;
#JsonProperty(required = false)
private Map<String, String> errors = new HashMap<>();
JsonItem() {
}
public boolean getSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Map<String, String> getErrors() {
return errors;
}
public void setErrors(Map<String, String> errors) {
this.errors = errors;
}
}
and have Object
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class DepositInfoDto implements Serializable {
private static final long serialVersionUID = -4123441934244992311L;
#NotNull
#JsonProperty(required = true)
private String productName;
#NotNull
#JsonProperty(required = true)
private String contractName;
#NotNull
#JsonProperty(required = true)
private List<ContractDto> contracts;
#NotNull
#JsonProperty(required = true)
private StatusDto status;
//...getters and setters
}
I recevied object like JsonItem<List<DepositInfoDto>>.
I try to create universal method to deserealize
public <T> List<T> getObjects(){
ObjectMapper mapper = new ObjectMapper();
List<T> myObjects = mapper.readValue(jsonInput, new TypeReference<JsonItem<List<T>>(){});
return myObjects;
}
Not work because T cast to Object in runtime
public List<DepositInfoDto> getObjects(){
ObjectMapper mapper = new ObjectMapper();
List<DepositInfoDto> myObjects = mapper.readValue(jsonInput, new TypeReference<JsonItem<List<DepositInfoDto >>(){});
return myObjects;
}
work but i want universal method because i have DepositInfoDto, CardinfoDto, ContractDto etc.
I see method
public List<T> getObjects(Class<T> clazz){
ObjectMapper mapper = new ObjectMapper();
List<T> myObjects = mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(List.class, clazz));
return myObjects;
}
but didn't work because i have JsonItem with data List<T>
How can i resolve this problem? Maybe mapper.getTypeFactory() have complex method like mapper.getTypeFactory().constructType(JsonItem.class, List.class,DepositInfoDto.class)
EDIT
In my case
ObjectMapper mapper = new ObjectMapper();
try {
JsonItem<T> item = mapper.readValue(objectWrapper.get(0), mapper.getTypeFactory().constructParametricType(
JsonItem.class, mapper.getTypeFactory().constructCollectionType(List.class, resourceClass)));
return item.getData();
} catch (IOException e) {
LOG.error("Can't deserialize JSON to class: "+ resourceClass +". Error: " + e);
Thread.currentThread().interrupt();
}
You can use TypeFactory#constructParametricType to create a JavaType for JsonItem<T> and then use TypeFactory#constructCollectionType to create CollectionType for List<JsonItem<T>>. Following is the example:
public <T> List<JsonItem<T>> getObjects(String jsonInput, Class<T> clazz) {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(
List.class, mapper.getTypeFactory().constructParametricType(JsonItem.class, clazz)));
}

Junit for Controller class

I have controller method and for it I am making Junit but getting Null pointer error when it calling a service method. I used power mock but still getting Null pointer.
method:
#RequestMapping(method = RequestMethod.GET, value = "/DSR.do")
public ModelAndView displayDataSourceReportPage(HttpServletRequest request,Model model) {
log.debug(" Inside displayDataSourceReportPage method ");
Map<String, Object> map = new HashMap<String, Object>();
try {
request.setAttribute(MENU_SELECTED, LABEL_MENU_SOURCEDATA);
request.setAttribute(SUB_MENU_SELECTED, LABEL_SUBMENU_DSR);
#SuppressWarnings("rawtypes")
List dataSource = dataSourceReportService.listDataSourceReportByCurrentRunInd("C");
map.put("dataSource", dataSource);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return new ModelAndView("DataSourceReport", "model", map);
}
test Method:
#InjectMocks
private DataSourceReportController dataSourceReportController;
#Mock
private DataSourceReportService dataSourceReportServiceImpl;
#InjectMocks
private DataSourceReportDAO dataSourceReportDAO = new DataSourceReportDAOImpl();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testdisplayDataSourceReportPage() throws Exception {
PowerMockito.mockStatic(DataSourceReport.class);
PowerMockito.mockStatic(HttpServletRequest.class);
PowerMockito.mockStatic(Model.class);
PowerMockito.mockStatic(DataSourceReportService.class);
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Model model = Mockito.mock(Model.class);
dataSourceReportServiceImpl = PowerMockito.mock(DataSourceReportService.class);
DataSourceReport dataSourceReport = PowerMockito.mock(DataSourceReport.class);
dataSourceReport.setCurrentRunInd("abc");
dataSourceReport.setActualFileName("Somthing");
dataSourceReport.setFileCountId(3);
dataSourceReport.setFileId(4);
dataSourceReport.setRecCount(3);
List<DataSourceReport> list = new ArrayList<DataSourceReport>();
list.add(dataSourceReport);
String currentRunInd = "currentRunInd";
Object obj =getClass();
PowerMockito.when(dataSourceReportDAO.listDataSourceReportByCurrentRunInd(currentRunInd)).thenReturn(list);
DataSourceReportController ctrl = new DataSourceReportController();
ctrl.displayDataSourceReportPage(request, model);
}
getting Null at "dataSourceReportService.listDataSourceReportByCurrentRunInd("C");"
You need to have this in the test class
PowerMockito.when(dataSourceReportService.listDataSourceReportByCurrentRunInd("C")).thenReturn(list);
before calling
ctrl.displayDataSourceReportPage(request, model);
Thanks # Arthur Zagretdinov
I tried the below code and it worked.
private MockMvc mockMvc;
#Mock
private HttpServletRequest req;
#Mock
private DataSourceReportService dataSourceReportServiceImpl;
#InjectMocks
private DataSourceReportController controller;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testdisplayDataSourceReportPage() throws Exception {
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Model model = Mockito.mock(Model.class);
DataSourceReport dataSourceReport =Mockito.mock(DataSourceReport.class);;
dataSourceReport.setCurrentRunInd("abc");
dataSourceReport.setActualFileName("Somthing");
dataSourceReport.setFileCountId(3);
dataSourceReport.setFileId(4);
dataSourceReport.setRecCount(3);
List<DataSourceReport> list = new ArrayList<DataSourceReport>();
list.add(dataSourceReport);
ModelAndView modelView = controller.displayDataSourceReportPage(request, model);
modelView.addObject(dataSourceReport);
}

JSON unmarshalling to POJO and inserting

I would like to unmarshal a json string to a pojo class.
I am reading it from an existing url:
https://builds.apache.org/job/Accumulo-1.5/api/json
I am using apache camel to unmarshal the url
#Component
public class RouteBuilder extends SpringRouteBuilder {
private Logger logger = LoggerFactory.getLogger(RouteBuilder.class);
#Override
public void configure() throws Exception {
logger.info("Configuring route");
//Properties die hij niet vindt in de klasse negeren
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
DataFormat reportFormat = new JacksonDataFormat(objectMapper, HealthReport.class);
from("timer://foo?fixedRate=true&delay=0&period=2000&repeatCount=1")
.routeId("accumoloToJsonRoute")
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.to("https://builds.apache.org:443/job/Accumulo-1.5/api/json")
.convertBodyTo(String.class)
.unmarshal(reportFormat) //instance van Build
.log(LoggingLevel.DEBUG, "be.kdg.teamf", "Project: ${body}")
.to("hibernate:be.kdg.teamf.model.HealthReport");
}
}
So far so good. I would like to only insert the 'healthReport' node using hibernate annotations.
#XmlRootElement(name = "healthReport")
#JsonRootName(value = "healthReport")
#Entity(name = "healthreport")
public class HealthReport implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int Id;
#Column
#JsonProperty("description")
private String description;
#Column
#JsonProperty("iconUrl")
private String iconUrl;
#Column
#JsonProperty("score")
private int score;
public HealthReport() {
}
public HealthReport(int score, String iconUrl, String description) {
this.score = score;
this.iconUrl = iconUrl;
this.description = description;
}
public String getDescription() {
return description;
}
public String getIconUrl() {
return iconUrl;
}
public int getId() {
return Id;
}
public int getScore() {
return score;
}
public void setDescription(String description) {
this.description = description;
}
public void setIconUrl(String iconUrl) {
this.iconUrl = iconUrl;
}
public void setId(int id) {
Id = id;
}
public void setScore(int score) {
this.score = score;
}
}
This is where the problem is. It does not recognize the annotations
and only null values are inserted in my database
#XmlRootElement(name = "healthReport")
#JsonRootName(value = "healthReport")
Does anybody know how to fix this?
Thanks
Fixed it using a Processor for my Route
public class HealthReportProcessor implements Processor {
#Autowired
private ConfigurationService configurationService;
#Override
public void process(Exchange exchange) throws Exception {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(exchange.getIn().getBody().toString());
ArrayNode report = (ArrayNode) root.get("healthReport");
int configId = configurationService.findJenkinsConfigurationByName(root.get("displayName").asText()).getId();
for (JsonNode node : report) {
JsonObject obj = new JsonObject();
obj.addProperty("description", node.get("description").asText());
obj.addProperty("iconUrl", node.get("iconUrl").asText());
obj.addProperty("score", node.get("score").asInt());
obj.addProperty("jenkinsConfig", configId);
exchange.getIn().setBody(obj.toString());
}
}
}
It is working but I think there is a better solution.
If you have a better solution please let me know ;)
Can you try this,
from("timer://foo?fixedRate=true&delay=0&period=2000&repeatCount=1")
.routeId("accumoloToJsonRoute")
.setHeader(Exchange.HTTP_METHOD,constant("GET"))
.to("https://builds.apache.org:443/job/Accumulo-1.5/apijson")
.unmarshal().json(JsonLibrary.Jackson, HealthReport.class)
And make sure the response params match the POJO fields.
Let me know if it works.