pass remoteUser value in HttpServletRequest to mockmvc perform test - spring

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() {
}
}

Related

How to correctly mock Interceptor pre handle method in spring boot integration tests

I'm writing an integration test to an API which receives #RequestAttribute List<String> permissions and HttpServletRequest request as method parameters. There is a custom interceptor which overrides the preHandle() method of HandlerInterceptor. This method receives HttpServletRequest request and HttpServletResponse response as parameters. Based on some logic there are some attributes set in HttpServletRequest request.
I'm writing an integration test where in I send an Http request to the endpoint of the application. I want to mock the interceptor and set these attributes myself.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#RunWith(SpringRunner.class)
public class TradeChargesTest {
#LocalServerPort
public int port;
#MockBean
AppInterceptor interceptor;
// other stuff
#BeforeEach
void initTest() throws Exception {
// Want to write the mock interceptor logic here.
}
public TestRestTemplate restTemplate = new TestRestTemplate();
public String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}
Test method:
public class UserInfoControllerTest extends TradeChargesTest {
TestRestTemplate restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
#Test
public void testUserInfoController(){
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity response = restTemplate.exchange(createURLWithPort("Testing/endpoint/user/v5/getUser?from_date=2022-04-01&page=1"), HttpMethod.GET, entity, Object.class);
assertEquals(200, response.getStatusCodeValue());
LinkedHashMap<String, Object> responseBodyMap = (LinkedHashMap<String, Object>) response.getBody();
assertEquals(3, responseBodyMap.get("totalHits"));
assertEquals(1, responseBodyMap.get("page"));
}
}

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

Why Mockito and Mockmvc don't work together

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

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