Junit5 test case for controller layer - java

#GetMapping(value = "/abc")
public ResponseDto<Map<String, FResponseDto>, Void> getFlightDetails(#RequestParam String fIds) {
Map<String, FResponseDto> response = fService
.getDetails(fIds);
if (Objects.isNull(response)) {
return ResponseDto.failure(FConstants.FLIGHT_NOT_FOUND);
}
return ResponseDto.success(FConstants.SUCCESS,response);
}
how to test this other then status i want to test the if and other return

This code may help you.
#WebMvcTest(controllers = YourController.class)
class YourControllerTest {
private MockMvc mockMvc;
#Autowired
private YourController controller;
#MockBean
private FService fService;
#BeforeEach
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(controller)
.build();
}
#Test
public void test_getFlightDetails() throws Exception {
Map<String, FResponseDto> data = ......;
Mockito.when(fService.getDetails(anyString())).thenReturn(data);
this.mockMvc.perform(get("/abc"))
.andExpect(status().isOk());
Mockito.when(fService.getDetails(anyString())).thenReturn(null);
this.mockMvc.perform(get("/abc"))
.andExpect(status().is5xxServerError());
}
}

Related

Why did the unit test fail?

I'm a new developer. Can someone tell me why did the following unit test fail?
Here is UserController.java
#RequiredArgsConstructor
#RestController
public class UserController {
private final UserService userService;
#PostMapping(value="/v1/user")
public ResponseEntity<ResponseDto> postUser(#RequestBody UserSaveRequestDto userSaveRequestDto) {
Long userId = userService.insertUser(userSaveRequestDto);
return CommonUtil.getResponseEntity(UserResponseDto.builder()
.userId(userId)
.build()
, HttpStatus.OK
, "회원 등록 완료");
}
}
Here is UserControllerTest.java
given(userService.insertUser(userSaveRequestDto)).willReturn(1L); // not working
so ".andExpect(jsonPath("$.data.userId").value("1"))" is fail
Please let me know why given() doesn't work.
#WebMvcTest
public class UserControllerTest {
MockMvc mockMvc;
#MockBean // Mock Bean은 Mock과 달리 Container가 관리하도록 빈을 만듬, 일반적으로 MockMvc와 많이씀
UserService userService;
#Autowired
ObjectMapper objectMapper;
#Autowired
private WebApplicationContext ctx;
UserSaveRequestDto userSaveRequestDto;
#BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(ctx)
.addFilters(new CharacterEncodingFilter("UTF-8", true)) // 한글 깨짐 처리
.build();
userSaveRequestDto = UserSaveRequestDto.builder()
.userName("test")
.userPhoneNumber("01026137832")
.build();
}
#DisplayName("MockMvc를 이용한 postUser slice 테스트")
#Test
public void postUserTest() throws Exception {
// given
given(userService.insertUser(userSaveRequestDto)).willReturn(1L); // Controller가 의존하고 있는 Service객체의 행동을 설정 해준다.
String content = objectMapper.writeValueAsString(userSaveRequestDto); // dto to json
// when
ResultActions resultActions = mockMvc.perform(post("/v1/user")
.contentType(MediaType.APPLICATION_JSON)
.content(content));
// then
resultActions
// ResultActions 객체의 andDo, andExpect, andReturn 메서드 사용
.andDo(result -> {
if (result.getResolvedException() != null) {
result.getResolvedException().printStackTrace();
}
})
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.userId").value("1"))
.andExpect(jsonPath("$.message").value("회원 등록 완료"));
}
}

No mapping for request with mockmvc

Currently struggling with problem when I get 'mapping error for request' with following controller/test configuration.
Controller:
#Slf4j
#Validated
#RestController
#RequiredArgsConstructor
public class AdtechController {
private final AdtechService adtechService;
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
log.trace("execute submitSession with {}", requestDto);
ResponseDtoresponse = adtechService.submitSession(requestDto);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#ExceptionHandler(AdtechServiceException.class)
public ResponseEntity<AdtechErrorResponse> handleAdtechServiceException(AdtechServiceException e) {
return new ResponseEntity<>(new AdtechErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#SpringJUnitConfig({AdtechTestConfig.class})
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#Test
public void testSubmitSession() throws Exception {
RequestDto requestDto = new RequestDto ();
requestDto.setKyivstarId("1123134");
requestDto.setMsisdn("123476345242");
requestDto.setPartnerId("112432523");
requestDto.setPartnerName("125798756");
String request = OBJECT_MAPPER.writeValueAsString(requestDto);
System.out.println("REQUEST: " + request);
String response = OBJECT_MAPPER.writeValueAsString(new ResponseDto("123"));
System.out.println("RESPONSE: " + response);
mockMvc.perform(post("/subscriber/session")
.content(MediaType.APPLICATION_JSON_VALUE)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(response)));
}
}
Configuration:
#Configuration
public class AdtechTestConfig {
#Bean
public AdtechService adtechTestService() {
return requestDto -> new AdtechResponseDto("123");
}
}
After test execution I get No mapping for POST /subscriber/session
The reason for the struggle is that my code from other modules with the same configuration works fine. Can somebody point out what am I missing ? Thanks in advance!
Apparently you are loading a configuration class to mock beans, this interferes with the other parts of Spring Boot and probably leads to partially loading your application. I suspect only the mocked service is available.
Instead of the test configuration use #MockBean to create a mock for the service and register behaviour on it.
#SpringBootTest
#AutoConfigureMockMvc
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#MockBean
private AdtechService mockService;
#BeforeEach
public void setUp() {
when(mockService.yourMethod(any()).thenReturn(new AdtechResponseDto("123"));
}
#Test
public void testSubmitSession() throws Exception {
// Your original test method
}
}
If the only thing you want to test is your controller you might also want to consider using #WebMvcTest instead of #SpringBootTest.
#WebMvcTest(AdTechController.class)
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#MockBean
private AdtechService mockService;
#BeforeEach
public void setUp() {
when(mockService.yourMethod(any()).thenReturn(new AdtechResponseDto("123"));
}
#Test
public void testSubmitSession() throws Exception {
// Your original test method
}
}
This will load a scaled-down version of the context (only the web parts) and will be quicker to run.
try this:
#Slf4j
#Validated
#RestController
#RequiredArgsConstructor
public class AdtechController {
private AdtechService adtechService;
public AdtechController (AdtechService adtechService) {
this.adtechService= adtechService;
}
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
log.trace("execute submitSession with {}", requestDto);
ResponseDtoresponse = adtechService.submitSession(requestDto);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#ExceptionHandler(AdtechServiceException.class)
public ResponseEntity<AdtechErrorResponse> handleAdtechServiceException(AdtechServiceException e) {
return new ResponseEntity<>(new AdtechErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#SpringJUnitConfig({AdtechTestConfig.class})
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#Autowired
private AdtechService adtechService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mvc = MockMvcBuilders.standaloneSetup(new AdtechController(adtechService)).build();
}
#Test
public void testSubmitSession() throws Exception {
RequestDto requestDto = new RequestDto ();
requestDto.setKyivstarId("1123134");
requestDto.setMsisdn("123476345242");
requestDto.setPartnerId("112432523");
requestDto.setPartnerName("125798756");
String request = OBJECT_MAPPER.writeValueAsString(requestDto);
System.out.println("REQUEST: " + request);
String response = OBJECT_MAPPER.writeValueAsString(new ResponseDto("123"));
System.out.println("RESPONSE: " + response);
mockMvc.perform(post("/subscriber/session")
.content(MediaType.APPLICATION_JSON_VALUE)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(response)));
}
}
Is the AdtechTestConfig.class introducing the /ad-tech path segment in to your test request? If so, this is why your test is trying the path /ad-tech/subscriber/session instead of /subscriber/session.
If this is actually the correct uri, then you may add #RequestMapping to the controller like below or just to the post method itself
#Slf4j
#Validated
#RestController
#RequestMapping("/ad-tech")
#RequiredArgsConstructor
public class AdtechController {
private final AdtechService adtechService;
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
...

How to init an object in a JUnit test?

I am trying to do a JUnit test to test a Controller.
My Controller consists of:
#Autowired
private OrderManager orderManager;
#RequestMapping(value = "/getOrderList", method = RequestMethod.POST)
#ResponseBody
public Map<String, Object> getOrderTables(OrderSearchDto orderSearchDto) {
...
orderHdrTables = orderManager.findAllOrders(orderSearchDto);
...
}
and my test is:
#RunWith(MockitoJUnitRunner.class)
public class FilterActivityTest {
#InjectMocks
private OrderHdrController orderHdrController;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(orderHdrController).build();
}
#Test
public void testActivityFilter() throws Exception {
OrderSearchDto orderSearchDto = new OrderSearchDto();
OrderSearchPanelDto orderSearchPanelDto = new OrderSearchPanelDto();
List <String> activityTypes = Arrays.asList("DELIVERY","START_UPLOAD");
orderSearchPanelDto.setActivityTypes(activityTypes);
orderSearchDto.setOrderSearchPanelDto(orderSearchPanelDto);
mockMvc.perform(MockMvcRequestBuilders.post("/orders/getOrderList")
.content(asJsonString(orderSearchDto))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.data[0].tripNo", is("SG1606LLR08469")))
.andExpect(jsonPath("$.data.data[1].tripNo", is("SG1606LLR08470")));;
}
private static String asJsonString(final Object obj) {
try {
final ObjectMapper mapper = new ObjectMapper();
final String jsonContent = mapper.writeValueAsString(obj);
return jsonContent;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
But during debug of the test, I am getting orderManager is null in my Controller. What can I do to initialise it?
I have modified your test a bit. Please try this.
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
FilterActivityTest.Config.class,
OrderHdrController.class,
})
public class FilterActivityTest {
#Configuration
static class Config {
#Bean
OrderManager orderManager() {
return mock(OrderManager.class);
}
}
#Autowired
private OrderHdrController orderHdrController;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(orderHdrController).build();
//remember to mock orderManager.findAllOrders here
}
}
You need to initialize the mocks
Update your #BeforeEach method like this:
#Mock
private OrderManager orderManager;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(orderHdrController).build();
}
Also, you may not need #RunWith(MockitoJUnitRunner.class)

How do I test a custom Spring Boot Actuator endpoint?

I have a spring boot actuator and WebMvc test isn't working. It returns an empty body. How would I test this?
#Configuration
#ManagementContextConfiguration
public class TestController extends AbstractMvcEndpoint
{
public TestController()
{
super( "/test", false, true );
}
#GetMapping( value = "/get", produces = MediaType.APPLICATION_JSON_VALUE )
#ResponseBody
public OkResponse getInfo() throws Exception
{
return new OkResponse( 200, "ok" );
}
#JsonPropertyOrder( { "status", "message" } )
public static class OkResponse
{
#JsonProperty
private Integer status;
#JsonProperty
private String message;
public OkResponse(Integer status, String message)
{
this.status = status;
this.message = message;
}
public Integer getStatus()
{
return status;
}
public String getMessage()
{
return message;
}
}
}
When I try to test it with the below, it doesn't work. I get an empty body in the return.
#RunWith( SpringJUnit4ClassRunner.class )
#DirtiesContext
#WebMvcTest( secure = false, controllers = TestController.class)
#ContextConfiguration(classes = {TestController.class})
public class TestTestController
{
private MockMvc mockMvc;
private ObjectMapper mapper;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup()
{
//Create an environment for it
mockMvc = MockMvcBuilders.webAppContextSetup( this.webApplicationContext )
.dispatchOptions( true ).build();
mapper = new ObjectMapper();
}
#SpringBootApplication(
scanBasePackageClasses = { TestController.class }
)
public static class Config
{
}
#Test
public void test() throws Exception
{
//Get the controller's "ok" message
String response = mockMvc.perform(
get("/test/get")
).andReturn().getResponse().getContentAsString();
//Should be not null
Assert.assertThat( response, Matchers.notNullValue() );
//Should be equal
Assert.assertThat(
response,
Matchers.is(
Matchers.equalTo(
"{\"status\":200,\"message\":\"ok\"}"
)
)
);
}
}
Here's a test I wrote to do something like what you are talking about. This test validates that our only the actuator endpoints we want to expose are available.
This is using SpringBoot 1.5.
I found the question here helpful: Unit testing of Spring Boot Actuator endpoints not working when specifying a port.
#RunWith(SpringRunner.class)
#SpringBootTest
#TestPropertySource(properties = {
"management.port="
})
public class ActuatorTests {
#Autowired
private WebApplicationContext context;
#Autowired
private FilterChainProxy springSecurityFilterChain;
private MockMvc mvc;
#Before
public void setup() {
context.getBean(MetricsEndpoint.class).setEnabled(true);
mvc = MockMvcBuilders
.webAppContextSetup(context)
.alwaysDo(print())
.apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
.build();
}
#Test
public void testHealth() throws Exception {
MvcResult result = mvc.perform(get("/health")
.with(anonymous()))
.andExpect(status().is2xxSuccessful())
.andReturn();
assertEquals(200, result.getResponse().getStatus());
}
#Test
public void testRestart() throws Exception {
MvcResult result = mvc.perform(get("/restart")
.with(anonymous()))
.andExpect(status().is3xxRedirection())
.andReturn();
assertEquals(302, result.getResponse().getStatus());
assertEquals("/sso/login", result.getResponse().getRedirectedUrl());
}
}

spring boot controller test, mockMov doesn't mock

I use Spring MVC and Spring boot to write a Restful service. This code works fine through postman.While when I do the unit test for the controller to accept a post request, the mocked myService will always initialize itself instead of return a mocked value defined by when...thenReturn... I use verify(MyService,times(1)).executeRule(any(MyRule.class)); and it shows the mock is not used.
I also tried to use standaloneSetup for mockMoc, but it complains it can't find the mapping for the path "/api/rule".
Could anybody help to figure out the problem?
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class MyControllerTest {
#Mock
private MyService myService;
#InjectMocks
private MyController myRulesController;
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void controllerTest() throws Exception{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
Long userId=(long)12345;
MyRule happyRule = MyRule.createHappyRule(......);
List<myEvent> mockEvents=new ArrayList<myEvent>();
myEvents.add(new MyEvent(......));
when(myService.executeRule(any(MyRule.class))).thenReturn(mockEvents);
String requestBody = ow.writeValueAsString(happyRule);
MvcResult result = mockMvc.perform(post("/api/rule").contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isOk())
.andExpect(
content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
verify(MyService,times(1)).executeRule(any(MyRule.class));
String jsonString = result.getResponse().getContentAsString();
}
}
Below is my controller class, where MyService is a interface. And I have implemented this interface.
#RestController
#RequestMapping("/api/rule")
public class MyController {
#Autowired
private MyService myService;
#RequestMapping(method = RequestMethod.POST,consumes = "application/json",produces = "application/json")
public List<MyEvent> eventsForRule(#RequestBody MyRule myRule) {
return myService.executeRule(myRule);
}
}
Is api your context root of the application? If so remove the context root from the request URI and test. Passing the context root will throw a 404. If you intend to pass the context root then please refer the below test case. Hope this helps.
#RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
#InjectMocks
private MyController myRulesController;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = standaloneSetup(myRulesController).build();
}
#Test
public void controllerTest() throws Exception{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
MyController.User user = new MyController.User("test-user");
ow.writeValueAsString(user);
MvcResult result = mockMvc.perform(post("/api/rule").contentType(MediaType.APPLICATION_JSON).contextPath("/api")
.content(ow.writeValueAsString(user)))
.andExpect(status().isOk())
.andExpect(
content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
}
}
Below is the controller
/**
* Created by schinta6 on 4/26/16.
*/
#RestController
#RequestMapping("/api/rule")
public class MyController {
#RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public User eventsForRule(#RequestBody User payload) {
return new User("Test-user");
}
public static class User {
private String name;
public User(String name){
this.name = name;
}
}
}

Categories

Resources