Why Mockito and Mockmvc don't work together - spring

I'm trying to some basic mock tests. I want to return my ApiResponse when Mockmvc call the API but it doesn't.
#RunWith(MockitoJUnitRunner.class)
public class AuthControllerTest {
#Autowired
private MockMvc mockMvc;
#InjectMocks
AuthController authController;
#Mock
private AuthService authService;
#Before
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(authController).build();
}
#Test
public void authenticateUserShouldReturnStatusOk() throws Exception {
LoginRequest loginRequest = TestUtils.createLoginRequest();
AuthResponse authResponse = new AuthResponse("token", loginRequest.getUsername(), HttpStatus.OK);
when(authService.authenticateUser(loginRequest)).thenReturn(authResponse);
mockMvc.perform(post("/api/auth/login")
.contentType(APPLICATION_JSON)
.content(TestUtils.convertObjectToJsonBytes(loginRequest)))
.andExpect(status().isOk())
.andDo(print());
verify(authService, times(1)).authenticateUser(refEq(loginRequest));
}
}
MockMvc print result:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/auth/login
Parameters = {}
Headers = [Content-Type:"application/json", Content-Length:"49"]
Body = <no character encoding set>
Session Attrs = {}
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Process finished with exit code 0
Why isn't that ApiResponse called? I want mockmvc to return the answer I gave, but nothing changes.
Can you help me?

Give it a try with this order.
Mockito.when(serviceMock.methodname(params)).thenReturn(responseType);
String json = new Gson().toJson(param);
MockHttpServletRequestBuilder requestBuilder =
MockMvcRequestBuilders.post(BASE_ENDPOINT)
.content(json)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.characterEncoding(CharEncoding.UTF_8);
ResultActions resultActions = this.mockMvc.perform(requestBuilder);
resultActions
.andExpect(status().isOk())
.andExpect(
MockMvcResultMatchers.jsonPath("$.fields").value(param.value())));
verify(serviceMock, times(1)).method(param);

Related

Mockmvc returns empty response body even if response status is 200

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);
}

Mockito mock is giving null for given test cases

I am using the SpringRunner to run the Junit mockito test case , below is the class , i was trying to write the test case , but getting null object
public class AccountManager {
public String getToken() throws Exception {
#Autowired
RestClient restClient;
String auth = apiUserPrefix + apiUserName + BatchJobConstants.COLON + apiUserPassword;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(StandardCharsets.UTF_8));
String authHeader = BatchJobConstants.BASIC_SPACE + new String(encodedAuth);
String token= null;
MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
data.add("grant_type", "client_credential");
String accManagerUrl = accManagerHost+":"+accManagerPort+"/"+accManagerResPath;
RestResponseObject responseObject = null;
try {
responseObject = restClient.execute(accManagerUrl, HttpMethod.POST, data, String.class, authHeader);
if (responseObject != null && responseObject.getPayload() != null && responseObject.getStatusCode() == HttpStatus.OK) {
JsonElement responseJson = (JsonElement) responseObject.getPayload();
if (responseJson.isJsonObject()) {
token= responseJson.getAsJsonObject().get(BatchJobConstants.ACCESS_TOKEN).getAsString();
}catch(RunTimeException e) {
//e
}
return token;
}
//Junit test case
#RunWith(SpringRunner.class)
public class AccountManagerTest {
#InjectMocks
AccountManager accountManager;
#Mock
RestClient restClient;
#Test
public void getTokenAccMgrSucess() throws Exception {
RestResponseObject restResponseObject = Mockito.mock(RestResponseObject.class);
Mockito.when(restClient.execute(Mockito.anyString(), Mockito.any(HttpMethod.class),
Mockito.anyString(), Mockito.eq(String.class), Mockito.anyString())).thenReturn(restResponseObject);
String token = accountManagerTokenProvider.getToken();
Assert.assertEquals("Token value {} ", null, token);
}
}
But still the below code return null value even after mocking this, can you please help how to mock this.
responseObject = restClient.execute(accManagerUrl, HttpMethod.POST, data, String.class, authHeader);
Note: Only Mockito needs to use no powermockito
For Autowired fields you not only have to mock it but should bind the mocked class to the spring context. You have two options :
1. Mark the mocked class as primary bean
#Configuration
public class TestConfiguration {
#Bean
#Primary
public RestClient restClient() {
return Mockito.mock(RestClient.class);
}
}
2.Use #MockBean annotation
#MockBean
RestClient restClient;
More on this :
https://www.baeldung.com/injecting-mocks-in-spring
https://www.baeldung.com/java-spring-mockito-mock-mockbean
Finally worked with mockito only just user any() instead of anyString(), since the Object is not matching with string only
Mockito.when(restClient.execute(Mockito.any(), Mockito.any(HttpMethod.class),
Mockito.any(), Mockito.eq(String.class), Mockito.any())).thenReturn(restResponseObject);

MockMvc does not return created resource in post response

Normally when you post to a spring data rest endpoint the response contains the location header with the url to the newly created resource and the json representation of the new resource in its body.
But when I post to MockMvc like following:
#RunWith(SpringRunner.class)
#SpringBootTest
public class OrderRestTest {
#Autowired
private ObjectMapper objectMapper;
#Autowired
private WebApplicationContext context;
#Autowired
private OAuthHelper oAuthHelper;
private MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
public void testSuperuserCanCreateOrder() throws Exception {
RequestPostProcessor accessToken = oAuthHelper.addBearerToken("someSuperUser", "ROLE_SUPERUSER");
Order order = new Order();
order.salesMemo = "some sales memo";
String responseFromTestRestTemplate = objectMapper.writeValueAsString(order);
assertNotNull(responseFromTestRestTemplate);
mockMvc.perform(
post("/ErPApI/orders")
.with(accessToken)
.content(objectMapper.writeValueAsString(order))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is2xxSuccessful());
mockMvc.perform(
get("/ErPApI/orders")
.with(accessToken))
.andExpect(jsonPath("_embedded.orders", hasSize(1)))
.andExpect(jsonPath("_embedded.orders[0].salesMemo", is("some sales memo")))
.andReturn();
}
}
the post is successful but the response body is blank. Is there a way to simulate the real response with MockMvc? Is my setup wrong?
set the Accept header to application/json too in the request.

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);

pass remoteUser value in HttpServletRequest to mockmvc perform test

I have an api call as:
#RequestMapping(value = "/course", method = RequestMethod.GET)
ResponseEntity<Object> getCourse(HttpServletRequest request, HttpServletResponse response) throwsException {
User user = userDao.getByUsername(request.getRemoteUser());
}
I'm getting the user null when I call this from the test class like:
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Mockito.when(request.getRemoteUser()).thenReturn("test1");
MvcResult result = mockMvc.perform( get( "/course")
.contentType(MediaType.APPLICATION_JSON)
.andExpect( status().isOk() )
.andExpect( content().contentType( "application/json;charset=UTF-8" ) )
.andReturn();
When I debug request object I can see remoteUser=null. So how can I pass the value to remote user?
You can use RequestPostProcessor in order to modify the MockHttpServletRequest in any fashion you want. In your case:
mockMvc.perform(get("/course").with(request -> {
request.setRemoteUser("USER");
return request;
})...
And if you're stuck with older versions of Java:
mockMvc.perform(get("/course").with(new RequestPostProcessor() {
#Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
request.setRemoteUser("USER");
return request;
}
})...
In Kotlin to set remoteUser in the MockHttpServletRequest use the #WithMockUser annotation.
Add the dependency testImplementation("org.springframework.security:spring-security-test:4.0.4.RELEASE") in build.gradle.kts
Add the #WithMockUser(username = "user") in the test
#WebMvcTest(controllers = [DossierController::class])
internal class DossierControllerTest {
#MockkBean
lateinit var request: MockHttpServletRequest
#Test
#WithMockUser(username = "user")
fun createDossierTest() {
}
}

Resources