I try to test my method addPerson() in my controller, but when I execute the test I have status 200 with an empty body in MockHttpServletResponse. I would like to test the body response with jsonPath from MockMvcResultMatchers but I can't do it while the body is empty.
Here is my test:
#WebMvcTest(PersonController.class)
#ExtendWith(SpringExtension.class)
public class PersonControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private Model model;
#MockBean
private PersonService service;
#Test
public void addPersonTest() throws Exception {
this.mvc.perform(post("/person/add")
.contentType(MediaType.APPLICATION_JSON).content("{\"firstName\": \"Test\",\"lastName\": \"\",\"address\": \"\",\"city\": \"\",\"zip\": \"\",\"phone\": \"\",\"email\": \"\"}"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk());
}
Here is my controller with the method addPerson()
#RequestMapping("/person")
#RestController
public class PersonController {
#Autowired
Model model;
private static final Logger logger = LogManager.getRootLogger();
#Autowired
private PersonService personService;
#GetMapping("/")
public List<Person> allPerson() {
return personService.all();
}
#PostMapping("/add")
public List<Person> addPerson(#RequestBody Person person) {
List<Person> listPerson = this.personService.add(person);
logger.info("Request = #RequestBody = {}", person);
logger.info("Response {}", listPerson);
return listPerson;
}
And here is the service:
#Service
public class PersonService {
#Autowired
private Model model;
public PersonService(Model model2) {
this.model = model2;
}
public List<Person> add(Person person) {
List<Person> listPersons = model.getPersons();
listPersons.add(person);
return listPersons;
}
Thanks for your help.
As you mock the PersonService you have to provide its behaviour otherwise it always returns null. You can use when().thenReturn() from Mockito for this:
#WebMvcTest(PersonController.class)
#ExtendWith(SpringExtension.class)
public class PersonControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private Model model;
#MockBean
private PersonService service;
#Test
public void addPersonTest() throws Exception {
List<Person> personList = Arrays.asList(new Person()); // create list here
when(service.add(any(Person.class)).thenReturn(personList); // mock the behaviour of your PersonService bean
this.mvc.perform(post("/person/add")
.contentType(MediaType.APPLICATION_JSON).content("{\"firstName\": \"Test\",\"lastName\": \"\",\"address\": \"\",\"city\": \"\",\"zip\": \"\",\"phone\": \"\",\"email\": \"\"}"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk());
}
}
Related
I want to test this service that uses 3 repositorie implementing CrudRepository of JPA
#Service
public class ExpeditionService {
ArticleRepository articleRepository;
CustomerRepository customerRepository;
AdressRepository adressRepository;
public ExpeditionService(ArticleRepository articleRepository, CustomerRepository customerRepository, AdressRepository adressRepository) {
this.articleRepository = articleRepository;
this.customerRepository = customerRepository;
this.adressRepository = adressRepository;
}
public Set<Article> findArticleByOrderId(Long orderId) {
return articleRepository.findArticleByOrdersId(orderId);
}
public Optional<Customer> findCustomerById(Long customerId) {
return customerRepository.findById(customerId);
}
public Set<Adress> findAdressesByOrderId(Long orderId) {
return adressRepository.findAdressesByOrOrderAdressesId(orderId);
}
}
In my test I set up ExpeditionService and repositories
#ExtendWith(SpringExtension.class)
#DataJpaTest
public class ExpeditionServiceTest {
#Autowired
private ArticleRepository articleRepository;
#Autowired
private TypeAdresseRespository typeAdresseRespository;
#Autowired
private AdressRepository adressRepository;
#Autowired
OrderRepository orderRepository;
#Autowired
CustomerRepository customerRepository;
#Autowired
CountryRepository countryRepository;
ExpeditionService expeditionService = new ExpeditionService(articleRepository , customerRepository , adressRepository);
}
But when I launch test on no matter what kind of method I'm getting error that this repository is null
What should I do please?
Please rewrite your unit test case like this and try again.
#ExtendWith(MockitoExtension.class)
public class ExpeditionServiceTest {
#Mock
private ArticleRepository articleRepository;
#Mock
private AdressRepository adressRepository;
#Mock
CustomerRepository customerRepository;
ExpeditionService expeditionService;
#BeforeEach
void setUp(){
expeditionService = new ExpeditionService(articleRepository , customerRepository , adressRepository);
}
#Test
void test1() {
//test code
}
}
I'm new to testing controller and web layer.
I have Service which has methods to work with orders, and I have controller that has that service as dependency
OrderService:
#Service
public class OrderServiceImpl implements OrderService{
private OrderRepository orderRepository;
private Assembler<Order, OrderDto> orderDtoAssembler;
#Autowired
public OrderServiceImpl(OrderRepository orderRepository,Assembler<Order, OrderDto> orderDtoAssembler) {
this.orderRepository = orderRepository;
this.orderDtoAssembler = orderDtoAssembler;
}
#Override
#Transactional
public List<OrderDto> findFilSortOrders(Map<String, String> filters, String sortedColumn, boolean descending, int startRow, int rowsPerPage) {
return orderRepository.findFilSortOrders(filters, sortedColumn, descending, startRow, rowsPerPage)
.stream().map(orderDtoAssembler::mergeAggregateIntoDto).collect(Collectors.toList());
}
}
And Controller has several mapping and the one I want to test.
OrderController :
#Controller
public class OrderController {
private static final Logger LOGGER = LogManager.getLogger(OrderController.class);
private final CarCategoryService carCategoryService;
private final TaxiServiceMakeOrder serviceMakeOrder;
private final OrderService orderService;
private final UserService userService;
#Autowired
public OrderController(CarCategoryService carCategoryService, TaxiServiceMakeOrder serviceMakeOrder, OrderService orderService, UserService userService) {
this.carCategoryService = carCategoryService;
this.serviceMakeOrder = serviceMakeOrder;
this.orderService = orderService;
this.userService = userService;
}
#GetMapping("/admin/ordersJson")
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public List<OrderDto> getOrders(#RequestParam String sortBy,
#RequestParam String filter,
#RequestParam boolean descending,
#RequestParam int startRow,
#RequestParam int rowsPerPage) throws JsonProcessingException {
LOGGER.info("OrdersGetAction is invoked");
ObjectMapper mapper = new ObjectMapper();
Map<String, String> filters = null;
if (!filter.equals("{}")) {
filters = mapper.readValue(filter, new TypeReference<Map<String, String>>() {
});
}
List<OrderDto> getOrders = orderService.findFilSortOrders(filters, sortBy, descending, startRow, rowsPerPage);
System.out.println("Controller :"+getOrders.size());;//to check If it works
LOGGER.info("Filtered and Sorted Order count is {}", getOrders.size());
return getOrders;
}
}
My test util to generate dto :
public class OrderDtoUtil {
public static List<OrderDto> generateOrderDto(int count) {
return IntStream.range(0, count)
.mapToObj(i -> {
OrderDto orderDto = new OrderDto();
orderDto.setOrderId((long) i);
orderDto.setOrderDate(LocalDateTime.now());
orderDto.setOrderCost(500);
orderDto.setUserDestination("UserDestination");
orderDto.setUserAddress("UserAddress");
orderDto.setUserId((long) i);
orderDto.setCarId((long) i);
return orderDto;
}).collect(Collectors.toList());
}
}
My test class for controller :
class OrderControllerTest {
private CarCategoryService carCategoryService;
private TaxiServiceMakeOrder serviceMakeOrder;
private OrderService orderService;
private UserService userService;
private OrderController orderController;
private MockMvc mockMvc;
#BeforeEach
public void setUp() {
carCategoryService = mock(CarCategoryService.class);
serviceMakeOrder = mock(TaxiServiceMakeOrder.class);
orderService = mock(OrderService.class);
userService = mock(UserService.class);
orderController = new OrderController(carCategoryService, serviceMakeOrder, orderService, userService);
mockMvc = standaloneSetup(orderController)
.defaultRequest(get("/")
.contextPath("/petProject_war_exploded")
.accept(MediaType.ALL)).build();
}
#Test
void getOrders() throws Exception {
List<OrderDto> orderDtos = OrderDtoUtil.generateOrderDto(3);
System.out.println("TEST method :"+orderDtos.size());
when(orderService.findFilSortOrders(anyMap(), anyString(), anyBoolean(), anyInt(), anyInt())).thenReturn(orderDtos);
mockMvc.perform(get("/petProject_war_exploded/admin/ordersJson")
.param("filter", "{}")
.param("sortBy", "orderId")
.param("descending", "false")
.param("startRow", "0")
.param("rowsPerPage", "3"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[0].orderId", is(orderDtos.get(0).getOrderId())))
.andExpect(jsonPath("$[1].orderId", is(orderDtos.get(1).getOrderId())))
.andExpect(jsonPath("$[2].orderId", is(orderDtos.get(2).getOrderId())));
}
}
And It fails on hasSize method because It shows that size is 0.
Result :
Can you explain why does it happen?
I have a #Component class:
#Component
#ServerEndpoint("/ws")
public class WebSocketHandler {
#Autowired
private UserService userService;
#OnOpen
public void onOpen(Session session) throws IOException, EncodeException {
List<User> users = userService.findAllByOnlineIsTrue();
session.getBasicRemote().sendObject(new RestResponse(Status.SUCCESSFUL, "online users", users));
System.out.println("Open WebSocket connection...");
}
}
UserService is an interface and it has an implementation:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private MongoTemplate template;
//...
}
When the onOpen method of WebSocketHandler was called, it threw NullPointerException because the userService was null. It's weird because I also have a controller class and userService is fine:
#RestController
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = "/login", method = RequestMethod.POST)
#ResponseBody
public RestResponse login(#RequestParam(name = "username") String username,
#RequestParam(name = "password") String password,
HttpServletRequest request) {
User user = userService.findUserByUsernameAndPassword(username, password);
// ....
}
}
I don't understand it. Could anyone help?
I'm using Spring Boot, Spring Data REST, Spring HATEOAS. I created a #RepositoryRestController:
#Api(tags = "Ticket Entity")
#RepositoryRestController
#PreAuthorize("isAuthenticated()")
public class TicketController extends RevisionController<TransitCertificate> {
private Logger log = LogManager.getLogger();
#Autowired
private LocalValidatorFactoryBean validator;
#Autowired
private TicketService ticketService;
#Autowired
private EnumTranslator enumTranslator;
#SuppressWarnings("rawtypes")
#Autowired
private PagedResourcesAssembler pagedResourcesAssembler;
#Autowired
private MessageSource messageSource;
#Autowired
private Javers javers;
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(validator);
}
#PostMapping(path = "/tickets")
public ResponseEntity<?> save(#RequestBody(required = true) #Valid Ticket ticket, PersistentEntityResourceAssembler resourceAssembler) {
return new ResponseEntity<>(resourceAssembler.toResource(ticketService.save(ticket)), HttpStatus.OK);
}
}
I need to intercept the event before the Ticket object is persisted. I created my handler:
#Component
#RepositoryEventHandler(Ticket.class)
public class TicketHandler {
private Logger log = LogManager.getLogger();
#Autowired
private WorkShiftRepository workShiftRepository;
#HandleBeforeCreate
public void handleBeforeCreates(Ticket ticket) {
WorkShift workShift = workShiftRepository.findByAgentUsernameAndEndDateIsNull();
if (workShift != null) {
ticket.setWorkShift(workShift);
}
}
}
and this is my TicketRepository:
#Transactional
#PreAuthorize("isAuthenticated()")
public interface TicketRepository extends PagingAndSortingRepository<Ticket, Long> {
#RestResource(exported = false)
#Override
public <S extends Ticket> Iterable<S> save(Iterable<S> entities);
#RestResource(exported = false)
#Override
public <S extends Ticket> S save(S entity);
#RestResource(exported = false)
#Override
public void delete(Long id);
#RestResource(exported = false)
#Override
public void delete(Ticket entity);
#Query(value = "SELECT MAX(number) FROM Ticket t WHERE t.block=:ticketBlock")
public Long findMaxNumber(#Param("ticketBlock") TicketBlock ticketBlock);
}
as described in the documentation but the event is not emitted. Like described here I'm using the #HandleBeforeCreate annotation. Am I doing something wrong?
I wrote this Webservice using Spring Data MVC:
Rest Controller
#RestController
#RequestMapping("/textmessages")
public class TextMessageRestController {
#Autowired
private TextMessageService textMessageService;
#RequestMapping(value = "/send", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.CREATED)
public void insertTextMessage(#RequestBody TextMessage.TextMessageDTO textMessageDTO) {
textMessageService.save(textMessageDTO);
}
}
Spring Service
#Service
#Transactional
public class TextMessageService {
#Autowired
private TextMessageRepository textMessageRepository;
#Autowired
private UserService userService;
public void save(TextMessage message) {
textMessageRepository.save(message);
}
public void save(TextMessage.TextMessageDTO textMessageDTO) {
save(from(textMessageDTO));
}
public TextMessage from(TextMessage.TextMessageDTO textMessageDTO) {
User sender = userService.from(textMessageDTO.getSender());
User receiver = userService.from(textMessageDTO.getReceiver());
return new TextMessage(receiver, sender, textMessageDTO.getSymmetricKeyEncrypted(), textMessageDTO.getText());
}
}
DTO - a static inner class
//This annotations are from Lombok
#Getter
#Setter
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public static class SenderReceiverDTO {
private String username;
private String pk;
public static SenderReceiverDTO from(User user) {
SenderReceiverDTO dto = new SenderReceiverDTO(user.username, user.pk);
return dto;
}
}
When I try to consume that REST Service, I get following Exception:
Consuming the rest service
public class RestService {
private static final String REST_STRING = "http://localhost:8080/cchat/";
private static final String TXT_MSG_STRING = REST_STRING + "textmessages/";
private static final String SEND_TXT_MSG = TXT_MSG_STRING + "send/";
private final RestTemplate restTemplate;
public RestService() {
this.restTemplate = new RestTemplate();
}
#SuppressWarnings("unchecked")
public List<TextMessage.TextMessageDTO> loadTextMessages(User.UserIdentifyingDTO userIdentifyingDTO) {
return restTemplate.postForObject(RECEIVE_TXT_MSG, userIdentifyingDTO, List.class);
}
}
i get the excpetion
org.springframework.web.client.HttpClientErrorException: 400 Bad Request
at foo.RestService.sendTextMessage(RestService.java:33)
Tests prove that the server-side is working properly!
Any ideas what may cause the problem?