Mockmvc returns empty response body even if response status is 200 - spring-boot

I am trying to learn Junit and I ended up in a situation where my testcase returns 200 status code but returns null response Body. Its just a simple save operation using JPA repo and I have tried many online solutions but none worked for me.
Testclass :
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
class CarManufacturingSystemApplicationTests {
#Autowired
private MockMvc mockMvc;
#MockBean
private GroupController groupController;
ObjectMapper om = new ObjectMapper();
#Test
public void createGroupTest() throws Exception {
GroupCreateRequest createRequest = new GroupCreateRequest();
createRequest.setActiveFlag(true);
createRequest.setGroupName("test");
createRequest.setPlantCode(1L);
String expectedjson = "{\r\n" + "\"message\": \"Group created successfully\"\r\n" + "}";
MvcResult result = mockMvc.perform(post("/group/createGroup")
.contentType(MediaType.APPLICATION_JSON_VALUE).accept(MediaType.APPLICATION_JSON_VALUE).content(new Gson().toJson(createRequest)))
.andExpect(status().isOk())
.andReturn();
String actualJson = result.getResponse().getContentAsString();
Assert.assertEquals(expectedjson, actualJson);
}
Controller:
#RestController
#RequestMapping(value = "/group")
public class GroupController {
#Autowired
private GroupService groupService;
#PostMapping("/createGroup")
public ResponseEntity<Response> createGroup(#RequestBody GroupCreateRequest groupCreateRequest) {
Response response = groupService.createGroup(groupCreateRequest);
return new ResponseEntity<> (response, HttpStatus.OK);
}
}
Error:
org.junit.ComparisonFailure: expected:<[{
"message": "Group created successfully"
}]> but was:<[]>
at org.junit.Assert.assertEquals(Assert.java:115)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.nissan.car.manufacturing.system.CarManufacturingSystemApplicationTests.createGroupTest(CarManufacturingSystemApplicationTests.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
Service implementation
public Response createGroup(GroupCreateRequest groupCreateRequest) {
Group group = new Group();
Response response = new Response();
try {
addGroupDetails(groupCreateRequest, group);
groupRepository.save(group);

Note that your are testing GroupController, not GroupService, so you should mock the GroupService. Please replace
#MockBean
private GroupController groupController;
to
#MockBean
private GroupService groupService;
And then using simple stubbing directives when(something).thenReturn(somethingElse) to make your groupService return the response you specified.
#Test
public void createGroupTest() throws Exception {
// ...
Response response = new Response();
response.setMessage("Group created successfully");
when(groupService.createGroup(any())).thenReturn(response);
// ...
Assert.assertEquals(expectedjson, actualJson);
}

Related

Why Testing Controller not working with #RunWith(SpringRunner.class) & #WebMvcTest annotation?

I am getting the below error when I try to run my controller test. Please can you let me know what I am missing? Why should I add the #ContextConfiguration or #SpringBootTest ?
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
#Controller
public class BasketController {
#Autowired
private BasketService basketService;
#GetMapping(value="/baskets/{basketId}")
public ResponseEntity<BasketDto> getBasket(#PathVariable("basketId") UUID basketId){
Basket basket = basketService.getBasket(basketId);
BasketDto dto = toBasketDto(basket);
ResponseEntity response = ResponseEntity.status(HttpStatus.OK).body(dto);
return response;
}
private BasketDto toBasketDto(Basket basket){
BasketDto dto = new BasketDto(basket.getBasketId(), basket.getItems());
return dto;
}
}
#RunWith(SpringRunner.class)
#WebMvcTest(BasketController.class)
public class BasketControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private BasketService basketService;
#Test
public void testGetItemsInBasketSuccessfully() throws Exception {
UUID basketId = UUID.randomUUID();
String URI = "/api/baskets/" + basketId;
Basket mockBasket = new Basket(basketId);
Mockito.when(basketService.getBasket(basketId)).thenReturn(mockBasket);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(URI).accept(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
String actualJson = result.getResponse().getContentAsString();
System.out.println(actualJson);
}
}

#Mock RestTemplate not returning expected value

I am creating unit test for my service class:
#Service
#Slf4j
public class SsaOpeningService {
#Autowired
private MockDataInitializer mockDataInitializer;
#Qualifier("restHttpsTemplateClient")
#Autowired
private RestTemplate restTemplate;
#Value("${acc-opening-casa.open-ssa}")
private String openSSAaccountUrl;
public CompletableFuture<AccountData> openSsa(
ApplicationDto items,
HttpHeaders headers,
BigInteger cifNo) {
log.info("Initializing headers");
HeaderRequest headerRequest = new HeaderRequest();
HttpHeaders header = headerRequest.initHeader(headers);
CurrentAcctReqBody request = CurrentAcctReqBody.builder()
.cifNo(cifNo)
.currencyType(SGD_CURRENCY)
.acName1(items.getApplicationData().getPersonalDetail().getName())
.productType(SSA_PRODUCT_CODE)
.noOfAccountHolders(BigInteger.ONE)
.accountType(ACC_TYPE)
.transactionRefNo(mockDataInitializer.randomIntInString(9))
.build();
log.info("Setting up entity for calling SSA opening.....");
HttpEntity<CurrentAcctReqBody> entity = new HttpEntity<>(request, header);
CurrentAcctResBody result = null;
try {
result = restTemplate
.postForObject(openSSAaccountUrl, entity, CurrentAcctResBody.class);
} catch (Exception e) {
log.info(e.getMessage());
}
System.out.println(14527);
System.out.println(result);
if(result !=null && result.getError()==null) {
AccountData accountData = AccountData.builder().build();
BeanUtils.copyProperties(result.getRbkAccountDetail(), accountData);
return CompletableFuture.completedFuture(accountData);
}
return null;
}
}
My test class:
#SpringBootTest
#RunWith(SpringRunner.class)
class SsaOpeningServiceTest {
#InjectMocks private SsaOpeningService ssaOpeningService;
#Autowired private MockDataInitializer dataInitializer;
#Mock private MockDataInitializer mockDataInitializer;
private static HttpHeaders headers = new HttpHeaders();
private static HeaderRequest ekycHeaderRequest = new HeaderRequest();
#BeforeAll
public static void init() {
headers = ekycHeaderRequest.initHeader();
}
#Qualifier("restHttpsTemplateClient")
#Mock private RestTemplate restTemplate;
#Test
void createSsa() throws IOException {
CurrentAcctResBody result = JSONUtils
.getObjectFromJson(DCResourceLoader.getResourceAsString("casa/ssa-res.json"), CurrentAcctResBody.class);
ApplicationDto items = ApplicationDto.builder().build();
Application application = dataInitializer.initialize();
BeanUtils.copyProperties(application, items);
when(restTemplate.postForObject(
any(String.class),
eq(HttpEntity.class),
eq(CurrentAcctResBody.class)))
.thenReturn(result);
System.out.println(1452);
System.out.println(result);
when(mockDataInitializer.randomIntInString(any(Integer.class)))
.thenReturn(dataInitializer.randomIntInString(9));
assertThat(ssaOpeningService.openSsa(items, headers, any(BigInteger.class))).isNull();
}
}
I have mocked my RestTemplate to return me the result I want. Problem is, it is not giving me the expected result. I have printed the result in both test class and service class. But in the service class it is always giving me null. I tried to give the most generic parameter when mocking but still doesnt work. The rest is working fine when running unit test EXCEPT for this part. Need assist on this. Thanks all!
#RunWith(MockitoJUnitRunner.class)
class SsaOpeningServiceTest {
#InjectMocks
private SsaOpeningService ssaOpeningService;
#Mock
private MockDataInitializer mockDataInitializer;
#Mock
private RestTemplate restTemplate;
#Test
void createSsa() throws IOException {
// some code
Mockito.when(restTemplate.postForObject(
nullable(String.class),
any(HttpEntity.class),
eq(CurrentAcctResBody.class)))
.thenReturn(result);
// some code
}
}

Test a method that returns a ResponseEntity from a service class - Spring boot

I have a service method which returns a ResponseEntity<>, when I am testing the rest endpoint it always returns below error.The error says that it haven't return the expected json.
java.lang.AssertionError: No value at JSON path "$.status"
This is the method I'am using
#Test
void Should_ReturnOk_When_VerifyOtpIsSuccessful() throws Exception {
ResponseWrapper responseWrapper =
new ResponseWrapper(ResponseStatusType.SUCCESS, "SUCCESSFULLY_VERIFIED", null);
ResponseEntity<ResponseWrapper> responseWrapperResponseEntity =new ResponseEntity<>(responseWrapper,HttpStatus.ACCEPTED);
when(otpService.verifySmsOtp(otpVerifyRequestDto)).thenReturn(responseWrapperResponseEntity);
this.mockMvc.perform(MockMvcRequestBuilders
.post(OTP_VERIFY_URI)
.contentType(MediaType.APPLICATION_JSON)
.header("app-key", "xxxx")
.content(asJsonString(otpVerifyRequestDto)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("S")))
;
}
Here ResponseWrapper is a model class
#Getter
public class ResponseWrapper {
private ResponseStatusType status;
private String message;
private String data;
public ResponseWrapper(ResponseStatusType statusType, String message, String data) {
this.status = statusType;
this.message = message;
this.data = data;
}
}
Could you help me out to sort this issue.
Edited:
Seems like the ResponseEntity does not return the JSON itself, it have other objects
Appreciate your input on this.
Test Class Initialization
#AutoConfigureMockMvc
public class OtpControllerTest {
#Mock
private OtpServiceImpl otpService;
private Validator validator = new Validator();
private OtpRequestDto otpRequestDtoEmail = otpRequestDto();
private OtpVerifyRequestDto otpVerifyRequestDto = otpVerifyRequestDto();
#InjectMocks
private OtpController otpController;
private MockMvc mockMvc;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
otpController = new OtpController(otpService, validator);
this.mockMvc = MockMvcBuilders.standaloneSetup(otpController).build();
}
// test methods here
//
}
Thank you.

When using MockMvc to test the controller, a parameter passing error occurred

I am using MockMvc to test the controller. Regarding parameter import, I encountered a type mismatch problem. I tried all the json styles.But nothing works
This is my controller class::
package app.dnatask.controller;
import ......;
#Slf4j
#RestController
#RequestMapping(value = "/API/scanresultconfigure")
public class ScanResultConfigureController extends BaseController {
#RequestMapping(value = "/queryScanResultList/{taskId}/{externalname}", method = RequestMethod.POST)
public IBaseResult queryscanResultList(final HttpServletRequest request, #PathVariable final String taskId, #PathVariable final String externalname, #RequestBody Map map) throws Exception {
return runController(new IControllRunner() {
public void run(IOutResult or, CheckResult cr) throws Exception {
......
}
}
}
}
This is my test class::
package app.dnatask.controller;
import ......
#WebAppConfiguration
#ContextConfiguration(classes = {ScanResultConfigureController.class})
#ComponentScan(
includeFilters = {
#ComponentScan.Filter(type = FilterType.CUSTOM,
value = {ScanResultConfigureController.class})
},
useDefaultFilters = false,
lazyInit = true
)
public class ScanResultConfigureControllerTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#BeforeMethod
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).dispatchOptions(true).build();
System.out.println("UT starting.............");
}
#AfterMethod
public void am() {
System.out.println("UT ending.............");
}
#Test
public void testQueryscanResultList() throws Exception {
Map<String, String> testMap = new HashMap<>();
testMap.put("key1", "value1");
testMap.put("key2", "value2");
String requestJson = JSONObject.toJSONString(testMap);
mockMvc.perform(
post("/API/scanresultconfigure/queryScanResultList/001/abc")
.contentType(MediaType.APPLICATION_JSON)
.param("map", requestJson)
)
.andExpect(status().isOk())
.andDo(print());
}
}
Error message::
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported
java.lang.AssertionError: Status expected:<200> but was:<415>
This is a project implemented by springmvc framework, I use TestNG for unit testing.
Regarding my problem, the solution is as follows::
MvcResult mvcResult = mockMvc.perform(
post("/API/scanresultconfigure/queryScanResultList/{taskId}/{externalname}", "123", "abc")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson)
)
.andExpect(status().isOk())
.andDo(print())
.andReturn();

Can not attach body to my POST request using Spring MockMvc

I'm trying to test my rest controller. No issues with GETs, but when I try to test a POST method I'm unable to attach the body.
private static final MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
private ObjectMapper jsonMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
#Test
public void test1() throws Exception {
//...Create DTO
//...Create same pojo but as entity
when(serviceMock.addEntity(e)).thenReturn(e);
mvc.perform(post("/uri")
.contentType(contentType)
.content(jsonMapper.writeValueAsString(dto))
)
.andDo(print())
.andExpect(status().isCreated())
.andExpect(content().contentType(contentType)); //fails because there is no content returned
}
This is the request output:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /uri
Parameters = {}
Headers = {Content-Type=[application/json;charset=UTF-8]}
There is no body. Why? I have printed jsonMapper.writeValueAsString(dto) and is not null.
edit:
Adding controller code:
#RestController
#RequestMapping("/companies")
public class CompanyController {
#Autowired
private CompanyService service;
#Autowired
private CompanyMapper mapper;
#RequestMapping(method=RequestMethod.GET)
public List<CompanyDTO> getCompanies() {
List<Company> result = service.getCompanies();
return mapper.toDtoL(result);
}
#RequestMapping(method=RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public CompanyDTO createCompany(#RequestBody #Valid CompanyDTO input) {
Company inputE = mapper.toEntity(input);
Company result = service.addCompany(inputE);
return mapper.toDto(result);
}
Solved.
The mock call should use any instead of a concrete object: when(serviceMock.addCompany(any(Company.class))).thenReturn(e);
I needed to override the equals method of the entity class to pass this statement: verify(serviceMock, times(1)).addCompany(e);

Resources