MockMvc empty response/return - java

I just created a simple integration test with MockMvc for a controller. All works well, but there is no response provided even the controller method returns something.
Here is the Controller:
import depmgmt.service.deposit.HouseService;
import depmgmt.service.dto.deposit.HouseDTO;
import depmgmt.serviceweb.common.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
#Controller
#RequestMapping("/rest/house")
public class HouseRestController extends BaseController {
private HouseService houseService;
#Autowired
public HouseRestController(HouseService houseService) {
this.houseService = houseService;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public List<HouseDTO> getHouses(#RequestParam(value = "page", defaultValue = "1") int page,
#RequestParam(value = "size", defaultValue = "50") int size) {
validatePageRequest(page, size);
return houseService.getHouseList(page, size);
}
}
Here is the test controller:
import com.fasterxml.jackson.databind.ObjectMapper;
import depmgmt.service.deposit.HouseService;
import depmgmt.service.dto.deposit.HouseDTO;
import depmgmt.serviceweb.config.SpringServiceWebConfig;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {SpringServiceWebConfig.class})
#WebMvcTest(controllers = HouseRestController.class)
public class HouseRestControllerTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private ObjectMapper objectMapper;
#MockBean
private HouseService houseService;
#Test
public void shouldGetHouses() throws Exception {
//given
List<HouseDTO> houseDTOS = new ArrayList<>();
HouseDTO houseDTO = HouseDTO.builder().country(null).city("City").owner(null).name("MyHouse").id(1l).address("HouseAddress").build();
houseDTOS.add(houseDTO);
when(houseService.getHouseList(1, 1)).thenReturn(houseDTOS);
//when
MvcResult mvcResult = mockMvc.perform(get("/rest/house/")
.contentType("application/json")
.param("page", "1")
.param("size", "1")).andReturn();
System.out.println(mvcResult.getResponse().getContentAsString());
}
}
When I execute the test the controller method is called successfully and it returns what it should:
HouseDTO houseDTO = HouseDTO.builder().country(null).city("City").owner(null).name("MyHouse").id(1l).address("HouseAddress").build();
houseDTOS.add(houseDTO);
when(houseService.getHouseList(1, 1)).thenReturn(houseDTOS);
However in the test Controller the: mvcResult.getResponse().getContentAsString() returns empty string:
What is wrong in the test?

The mistake what that there is no #ResponseBody on the method.
So either #RestController on the Class or #Controller on the class and #ResponseBody on the method.

Related

Spring boot with Mongo db rest Api

I have created a crud application Using spring boot initializer.
Dependencies:
Lombok
Spring Web
Spring Mongo
This app calls from a database/cluster that I have set up on atlas. but I want it to call the correct collection and just do a simple get all api call in postman
but I get a server 500 error
Service Java file:
package com.fullstack.app.Service;
import com.fullstack.app.exception.EntityNotFoundException;
import com.fullstack.app.Model.*;
import com.fullstack.app.Model.Request.WCCreationRequest;
import com.fullstack.app.Repository.StatusData_WCRepo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
#Service
#RequiredArgsConstructor
public class StatusDataService {
private static StatusData_WCRepo wcRepository;
public StatusData createData (WCCreationRequest request) {
StatusData statusData = new StatusData();
BeanUtils.copyProperties(request, statusData);
return wcRepository.save(statusData);
}
public static List<StatusData> getAllData() {
return wcRepository.findAll();
}
}
request:
package com.fullstack.app.Model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#Document(collection = "StatusData_WC")
public class StatusData {
#Id
private String ID_Number;
private String Surname;
private String Full_Names;
private String Address;
private String VR;
private Integer Ward;
private Integer VD_Number;
}
Controller:
package com.fullstack.app.Controller;
import com.fullstack.app.Model.StatusData;
import com.fullstack.app.Model.Request.WCCreationRequest;
import com.fullstack.app.Service.StatusDataService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import lombok.RequiredArgsConstructor;
#RestController
#RequestMapping(value = "/api/statusData")
#RequiredArgsConstructor
public class StatusDataController {
private final StatusDataService sdService;
#GetMapping("/statusdata")
public ResponseEntity getAllData(#RequestParam(required = false) String id) {
if (id == null) {
return ResponseEntity.ok(StatusDataService.getAllData());
}
return ResponseEntity.ok(StatusDataService.getAllData());
}
}
Application properties:
spring.data.mongodb.uri=mongodb+srv://*****:******#cluster0.wlmmf.mongodb.net/myFirstDatabase?retryWrites=true&w=majority

WebfluxTest and MockBean

I've got problem with mock. It's null. Could you help me?
UsersService
public interface UsersService {
Mono<GetUserDto> findById(String id);
Mono<GetUserDto> findByUsername(String username);
Mono<CreateUserResponseDto> create(Mono<CreateUserDto> createUserDtoMono);
}
RoutingHandlers
package com.app.routing;
import com.app.dto.CreateUserDto;
import com.app.service.UsersService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
#Component
#RequiredArgsConstructor
public class RoutingHandlers {
private final UsersService usersService;
public Mono<ServerResponse> register(ServerRequest serverRequest) {
Mono<CreateUserDto> createUserDtoMono = serverRequest.bodyToMono(CreateUserDto.class);
var create = usersService.create(createUserDtoMono);
return toServerResponse(create, HttpStatus.CREATED);
}
public Mono<ServerResponse> findByUsername(ServerRequest serverRequest) {
String username = serverRequest.pathVariable("username");
return toServerResponse(usersService.findByUsername(username), HttpStatus.OK);
}
public Mono<ServerResponse> findById(ServerRequest serverRequest) {
String id = serverRequest.pathVariable("id");
return toServerResponse(usersService.findById(id), HttpStatus.OK);
}
private static <T> Mono<ServerResponse> toServerResponse(Mono<T> mono, HttpStatus status) {
return mono
.flatMap(item -> ServerResponse
.status(status)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(item)))
.doOnError(err -> {
System.out.println("---------------------------- ERROR -----------------------------");
System.out.println(err);
System.out.println("----------------------------------------------------------------");
})
.onErrorResume(e -> ServerResponse
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(e.getMessage())));
}
}
Routing
package com.app.routing;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.nest;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
#Configuration
public class Routing {
#Bean
public RouterFunction<ServerResponse> routerFunction(RoutingHandlers routingHandlers) {
return nest(
path("/users"),
route(POST("").and(accept(MediaType.APPLICATION_JSON)), routingHandlers::register)
.andRoute(GET("/username/{username}").and(accept(MediaType.APPLICATION_JSON)), routingHandlers::findByUsername)
.andRoute(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), routingHandlers::findById)
);
}
}
RoutingTest
package com.app;
import com.app.dto.CreateUserDto;
import com.app.dto.CreateUserResponseDto;
import com.app.routing.Routing;
import com.app.routing.RoutingHandlers;
import com.app.service.UsersService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Mono;
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {RoutingHandlers.class, Routing.class})
#WebFluxTest
class RoutingTest {
#Autowired
private ApplicationContext applicationContext;
#MockBean
private UsersService usersService;
private WebTestClient webTestClient;
#BeforeEach
public void setup() {
webTestClient = WebTestClient.bindToApplicationContext(applicationContext).build();
}
#Test
public void test1() {
var userBody = CreateUserDto
.builder()
.username("u")
.password("1234")
.passwordConfirmation("1234")
.build();
var body = Mono.just(userBody);
var userResponse = CreateUserResponseDto
.builder()
.id("1")
.username("u")
.build();
var response = Mono.just(userResponse);
Mockito
.when(usersService.create(body))
.thenReturn(response);
webTestClient
.post()
.uri("/users")
.accept(MediaType.APPLICATION_JSON)
.body(body, CreateUserDto.class)
.exchange()
.expectStatus().isCreated()
.expectBody(CreateUserResponseDto.class)
.value(createUserResponseDto -> {
Assertions.assertThat(createUserResponseDto)
.hasFieldOrPropertyWithValue("username", "u")
.hasFieldOrPropertyWithValue("password", "1234");
});
}
}
DTOs
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class CreateUserDto {
private String username;
private String password;
private String passwordConfirmation;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class CreateUserResponseDto {
private String id;
private String username;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class GetUserDto {
private String id;
private String username;
private String password;
}
After I ran test I got error:
Cannot invoke "reactor.core.publisher.Mono.flatMap(java.util.function.Function)" because "mono" is null.
In RoutingHandlers in register method instance called create is null:
public Mono<ServerResponse> register(ServerRequest serverRequest) {
Mono<CreateUserDto> createUserDtoMono = serverRequest.bodyToMono(CreateUserDto.class);
var create = usersService.create(createUserDtoMono);
return toServerResponse(create, HttpStatus.CREATED);
}

There was an unexpected error (type=Method Not Allowed, status=405). Request method 'GET' not supported with spring boot

I'm trying to create delete function with Spring boot, reactjs and axios.
For first step, I just confirm if delete action is activated by entering URL directly.
But It doesn't work even if I enter URL directly.
I know GET is not supported but I don't know which I should fix.
Please tell me if you know.
ActionController.java
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.repository.CheckListRepository;
import com.example.demo.service.CheckListService;
#CrossOrigin
#RequestMapping("action/")
#RestController
public class ActionController {
#Autowired
CheckListRepository clr;
#Autowired
CheckListService cls;
#DeleteMapping(path = "{deleteId}")
public void deleteAction(#PathVariable Integer deleteId) {
clr.deletebyListNo(deleteId);
}
}
PS: This is axios code about contents.
Controller
package com.example.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.CheckList;
import com.example.demo.entity.CheckListForm;
import com.example.demo.repository.CheckListRepository;
import com.example.demo.service.CheckListService;
#CrossOrigin
#RestController
#RequestMapping("api/")
public class CheckListController {
#Autowired
private CheckListRepository checkListRepository;
#Autowired
private CheckListService cls;
#GetMapping("list")
public List<CheckListForm> getList() {
List<CheckList> checkList = this.checkListRepository.findAll();
List<CheckListForm> checkListForm = cls.entityToForm(checkList);
return checkListForm;
}
}
CheckList.js
import axios from 'axios'
const CHECKLIST_REST_API_URL = 'http://localhost:8080/api/list';
class CheckListService {
getList() {
return axios.get(CHECKLIST_REST_API_URL);
}
}
export default new CheckListService();
I could confirm delete action method in control is activated in the following way.
I changed code
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.repository.CheckListRepository;
import com.example.demo.service.CheckListService;
#CrossOrigin
#RequestMapping("action/")
#RestController
public class ActionController {
#Autowired
CheckListRepository clr;
#Autowired
CheckListService cls;
#DeleteMapping(path = "{deleteId}")
public void deleteAction(#PathVariable Integer deleteId) {
clr.deletebyListNo(deleteId);
}
}
to
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.repository.CheckListRepository;
import com.example.demo.service.CheckListService;
#CrossOrigin
#RequestMapping("action/")
#RestController
public class ActionController {
#Autowired
CheckListRepository clr;
#Autowired
CheckListService cls;
#RequestMapping(path = "{deleteId}")
public void deleteAction(#PathVariable Integer deleteId) {
clr.deletebyListNo(deleteId);
}
}

how can i get the object not map address?

I'm try to connect java spring boot with mysql. when i run the code i got the map address like this
This is my first code
This is EmpController1
package com.example.rest.controller;
import com.example.rest.repository.R1pro;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.rest.repository.EmpRepository1;
import java.util.ArrayList;
import java.util.List;
#RestController
#RequestMapping(value = "/emp")
#Slf4j
public class EmpController1 {
#Autowired
private EmpRepository1 empRepository1;
#RequestMapping(value="/ee", method = RequestMethod.GET)
#ResponseBody
public String getCategoryList() {
List<String> sj = new ArrayList<String>();
Gson gson= new Gson();
System.out.println(123);
List<R1pro> emps1 = this.empRepository1.findByLimit();
return emps1.toString();
}
}
This is my EmpRepository1 code
package com.example.rest.repository;
import com.example.rest.Emp;
import com.example.rest.Emp1;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface EmpRepository1 extends JpaRepository<Emp1, Integer> {
#Query(value = "select * from d_RANGE limit 1",nativeQuery = true)
public List<R1pro> findByLimit();
}
This is R1pro code
package com.example.rest.repository;
import java.util.Date;
public interface R1pro {
public String USER_ID();
public String CUST_GP();
}
This is my Emp1 code
package com.example.rest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Date;
import java.sql.Timestamp;
#Entity
#Table(name = "TEMP_TEST_M78_2W")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Emp1 {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String USER_ID;
private String CUST_GP;
}
This is my Application code
package com.example.rest;
import com.example.rest.repository.EmpRepository;
import com.example.rest.repository.EmpRepository1;
import com.example.rest.repository.R1pro;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.List;
#SpringBootApplication
#Slf4j
public class Application {
#Autowired
EmpRepository empRepository;
#Autowired
EmpRepository1 empRepository1;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
CommandLineRunner start() {
return args -> {mysql();};
}
private void mysql() {
List<R1pro> emp1 = this.empRepository1.findByLimit();
}
}
When i run the code i got this result
[org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap#27ae5583]
So i change the EmpController1 code
package com.example.rest.controller;
import com.example.rest.repository.R1pro;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.rest.repository.EmpRepository1;
import java.util.ArrayList;
import java.util.List;
#RestController
#RequestMapping(value = "/emp")
#Slf4j
public class EmpController1 {
#Autowired
private EmpRepository1 empRepository1;
#RequestMapping(value="/ee", method = RequestMethod.GET)
#ResponseBody
public String getCategoryList() {
List<String> sj = new ArrayList<String>();
Gson gson= new Gson();
System.out.println(123);
List<R1pro> emps1 = this.empRepository1.findByLimit();
for (int i =0; i<emps1.size();i++)
{
sj.add(emps1.get(i).USER_ID()+" "+ emps1.get(i).CUST_GP());
}
return sj.toString();
}
}
When i run the code i got this Error message
java.lang.IllegalArgumentException: Invoked method public abstract java.lang.String com.example.rest.repository.R1pro.USER_ID() is no accessor method!
Actually this method same as mysql data columns
USER_ID varchar(150)
CUST_GP varchar(1)
This is my sql columns informations
I don't know what is the problem also any solution.. so if someone knows that please teach me
I really admire to solve this issue
thank you!
You need to tweak your interface into something like this -
public interface R1pro {
String getUSER_ID();
String getCUST_GP();
}
The resultset is mapped only to the getter methods similar to the one created in Emp1 class

Spring StandardMultipartHttpServletRequest validation

Is there any possibility to validate StandardMultipartHttpServletRequest using standard #Valid annotation and custom Validator?
I've implemented such validator, annotated method param in controller the validator is not invoked.
I've figured it out myself. To make it work you need a DTO:
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
#Getter
#Setter
public class NewOrderFilesDTO {
List<MultipartFile> files;
}
Then, a validator:
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import static org.springframework.util.CollectionUtils.isEmpty;
#Component
public class NewOrderFilesValidator implements Validator {
private static final String MIME_TYPE_PDF = "application/pdf";
private static final long ALLOWED_SIZE = 3 * 1024 * 1024;
#Override
public void validate(Object target, Errors errors) {
if (target == null) {
return;
}
NewOrderFilesDTO newOrderFilesDTO = (NewOrderFilesDTO) target;
List<MultipartFile> newOrderFiles = newOrderFilesDTO.getFiles();
if (isEmpty(newOrderFiles)) {
return;
}
for (MultipartFile file : newOrderFiles) {
if (!MIME_TYPE_PDF.equals(file.getContentType())) {
errors.rejectValue(file.getName(), file.getName(), "'application/pdf' files allowed only!");
}
if (file.getSize() > ALLOWED_SIZE) {
errors.rejectValue(file.getName(), file.getName(), "File size allowed up to 3MB!");
}
}
}
#Override
public boolean supports(Class<?> cls) {
return NewOrderFilesDTO.class.equals(cls);
}
}
And finally a controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.Valid;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
#Controller
class OrderController {
private final NewOrderFilesValidator newOrderFilesValidator;
#Autowired
OrderController(NewOrderFilesValidator newOrderFilesValidator) {
this.newOrderFilesValidator = newOrderFilesValidator;
}
#InitBinder("newOrderFiles")
void initOrderFilesBinder(WebDataBinder binder) {
binder.addValidators(newOrderFilesValidator);
}
#ResponseStatus(NO_CONTENT)
#RequestMapping(value = ORDERS_PATH, method = POST, consumes = MULTIPART_FORM_DATA_VALUE)
void createOrder(
#Valid #ModelAttribute NewOrderFilesDTO newOrderFiles
) {
}
}
With the configuration above the DTO will be validated automatically by spring.

Categories