java.lang.AssertionError: Status expected:<200> but was:<400> in spring jersey controller - spring

it's my controller...
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Path("/categories")
public POSResponse getAllCategories() {
String countryCode="1";
return infoService.getAllCategories(countryCode);
}
it's my testController....
#Mock
InfoService infoService;
#InjectMocks
private InfoController infoController;
private MockMvc mockMvc;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(infoController).build();
}
#Test
public void getAllCategoriesTest() throws Exception {
POSResponse response=new POSResponse();
Category category=new Category();
category.setCountryCode(1);
category.setDescription("Mother Dairy");
response.setResponse(category);
when(infoService.getAllCategories("1")).thenReturn(response);
mockMvc.perform(get("/categories"))
.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(1)))
.andExpect(jsonPath("$.description", is("Mother Dairy")));
verify(infoService, times(1)).getAllCategories("1");
verifyNoMoreInteractions(infoService);
}
i am using jersey controller.
when i call the method i got error msg"java.lang.AssertionError: Status expected:<200> but was:<400>"

Whether you may use in your controller :
#Consumes(MediaType.APPLICATION_JSON) // instead of MediaType.APPLICATION_FORM_URLENCODED
Or, in you test :
mockMvc.perform(get("/categories")
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE))
...
Why?
An HTTP request should be in one of the media types accepted by the server, and MockMvc might use MediaType.APPLICATION_JSON (As my test show!). You can check it by printing the request detail:
mockMvc.perform(get("/categories")
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(MockMvcResultHandlers.print())
...

Related

java.lang.AssertionError: Status Expected :200 Actual :500

I wrote a small code to test my Controller and used mockito in this regard. The code is shown below with correct syntaxes
public class ApiTest {
private MockMvc mockMvc;
#InjectMocks
private PersonController personController;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(personController).build();
}
#Test
public void testPersonController() throws Exception{
//String jsonResult = "{\"name\": \"Müller\", \"lastName\": \"Hans\", \"zipCode\": \"67742\", \"city\": \"Lauterecken\", \"color\": \"blau\", \"id\": 1}";
mockMvc.perform(MockMvcRequestBuilders.
get("/api/v1/person/persons/1").
accept(MediaType.APPLICATION_JSON)).
andDo(print()).
andExpect(status().isOk()).
andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1")).
andExpect(MockMvcResultMatchers.jsonPath("$name").value("Müller"))
.andExpect(MockMvcResultMatchers.jsonPath("$lastName").value("Hans")).
andExpect(MockMvcResultMatchers.jsonPath("$zipCode").value("67742"))
.andExpect(MockMvcResultMatchers.jsonPath("$city").value("Lauterecken"))
.andExpect(MockMvcResultMatchers.jsonPath("$color").value("blau"));
}
}
I am receiving an assertion error as shown below
java.lang.AssertionError: Status
Expected :200
Actual :500
Can anyone help me where I am going wrong?
Looks like you're not fully utilizing what Spring Boot offers to test controllers.
When you're testing with MockMvc:
annotate your class with #WebMvcTest
use #MockBean to mock any collaborators this controller depends on
autowire MockMvc instead of creating it
#WebMvcTest(PersonController.class)
public class ApiTest {
#Autowired
private MockMvc mockMvc;
#MockBean
SomeService someService; // only if controller has dependencies on any components
#Test
void aTest() {
mockMvc.perform(...)
// ...
}

Testing the controller which returns response entity

I have following the controller which accepts post request and returns Response Entity with body
#RestController
public class UserController {
#Autowired
private UserService UserService;
#RequestMapping(value = "/all", method = POST,consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<ResponseUser>> navigationTree(#RequestBody(required=false) UserDataRequest request) {
return UserService.sendEntries(request);
}
}
This is the test I wrote I for it:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class UserControllerTest {
private MockMvc mockMvc;
#MockBean
private UserService UserServiceMock;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setUp() {
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void returnTopLevel() throws Exception {
String expectedJson = "[{\"id\":\"11\",\"name\":\"11\"},{\"id\":\"22\",\"name\":\"22\"}]";
MvcResult result = this.mockMvc.perform(post("/all")
.contentType(MediaType.APPLICATION_JSON)
.content("")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andReturn();
String actualJson = result.getResponse().getContentAsString();
// System.out.println(result);
//assertThat(Objects.equals(expectedJson, actualJson)).isTrue();
verify(UserServiceMock,times(1)).sendEntries(null);
}
}
I want to compare string received in response body to expected string.
I tried the string comparison but it's not working
Errors :
assertThat(Objects.equals(expectedJson, actualJson)).isTrue();
and actualjson is empty.
What are the other ways?
You need to mock the UserService to return something before executing this.mockMvc.perform. Something like this:
when(UserServiceMock.sendEntries(null)).thenReturn(expectedResponceEntity);
So just construct the expected response then mock UserService to return it.

Want to Mock ValidationofToken in restcontroller junit testing

Need to skip a Validation of token id login in controller for unit testing
Not sure what to use Mock or spy since i'm testing the controller itself
public class TestController extends BaseController {
#Autowired
TestService service;
#RequestMapping(value = "/test")
public #ResponseBody TestResponse getAll(#RequestBody TestRequest request) {
validateToken(request);
TestResponse response = service.getall(request);
response.setTokenID(request.getTokenID());
return response;
}
}
public class BaseController {
protected void validateToken(IRequest request) {
TokenResponse tokenresponse = restTemplate.exchange(TokenServiceURL, HttpMethod.GET, null, TokenResponse .class, tokenId).getBody();
User user = new user()
user.setUserRole(tokenresponse.getUser()));
request.setUser(user);
}
}
public class TestControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Autowired
private TestController testControlller;
#MockBean
private TestService testService;
BaseController baseControllerSpy = Mockito.spy(BaseController.class);
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
public void verifygetAll() throws Exception {
TestRequest request = new TestRequest();
TestResponse response = new Response();
**Mockito.doNothing().when(baseControllerSpy).validateTokenID(request);**
when(testService.get(request)).thenReturn(response);
mockMvc.perform(MockMvcRequestBuilders.post("/test")
.contentType(MediaType.APPLICATION_JSON)
.content(requestString)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
}
}
Base controller being spy doesn't seem to work, is there any other way i can approach this scenrio. please help
I can advice you two solutions:
I assume that if you are in the same package then you have to inject a spy of TestController in the mockMvc when you do the build() then you can create the validateToken mockMvc
doNothing().when((BaseController)testController).validateTokenID(any());
If the previous solution is not compliant then you can extend the TestController class with the TestControllerForTest and you can make the override of the validateTokenID method where you do nothing.

How to mock BindingResult in Spring Boot Test

I have the following controller:
#RestController
#RequestMapping(value = ROOT_MAPPING)
public class GatewayController {
#Autowired
private RequestValidator requestValidator;
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(requestValidator);
}
#PostMapping(value = REDIRECT_MAPPING)
public ResponseEntity<ResponseDTO> redirectEndpoint(#Validated #RequestBody RequestDTO requestDTO, BindingResult result) {
if (result.hasErrors()) {
// Handle validation errors
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
// Do other stuff
return ResponseEntity.status(HttpStatus.OK).build();
}
}
And this test class:
#RunWith(SpringRunner.class)
#WebMvcTest(GatewayController.class)
public class GatewayControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private RequestValidator requestValidator;
#MockBean
private BindingResult bindingResult;
private JacksonTester<RequestDTO> requestJacksonTester;
#Before
public void setUp() throws Exception {
JacksonTester.initFields(this, new ObjectMapper());
Mockito.when(requestValidator.supports(ArgumentMatchers.any())).thenReturn(true);
}
#Test
public void whenRedirectWithValidationErrorsThenBadRequestReturned() throws Exception {
RequestDTO request = new RequestDTO();
// Set some values
Mockito.when(bindingResult.hasErrors()).thenReturn(true);
mockMvc.perform(MockMvcRequestBuilders.post(ROOT_MAPPING + REDIRECT_MAPPING)
.contentType(MediaType.APPLICATION_JSON)
.content(requestJacksonTester.write(request).getJson()))
.andExpect(MockMvcResultMatchers.status().isBadRequest());
}
}
When I run this code the test case fail with this reason: Status
Expected :400
Actual :200
So, what I want to do is to mock the BindingResult which passed as a parameter to the redirectEndpoint method in the Controller so that when calling bindingResult.hasErrors() this should return true and the test case pass.
I did many search but with no luck. Any suggestions how to do that?
Thanks in advance.
BindingResult is not a bean in the ApplicationContext. Thus, you cannot mock it via #MockBean.
A BindingResult is created for you by Spring MVC for each incoming HTTP request.
Thus, you don't want to mock the BindingResult. In fact, you probably don't want to mock the behavior of your RequestValidator either. Rather, you should ideally use the real implementation of your RequestValidator, pass in invalid request data (via MockMvc), and then verify the response accordingly.
Note that you should be able to include the real implementation of your RequestValidator via #Import(RequestValidator.class) on the test class.

Spring Boot Test MockMvc perform post - Not working

I'm trying to make a Integration test using the Spring Boot but the post request is not working. The method saveClientePessoaFisica is never called and do not return any kind of error! I just tried to make other tests using a get method and it works properly.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("dev")
public class ClienteControllerIT {
#Autowired
private MockMvc mvc;
#Test
public void nao_deve_permitir_salvar_cliente_pf_com_nome_cpf_duplicado() throws Exception {
this.mvc.perform(post("/api/cliente/pessoafisica/post")
.contentType(MediaType.APPLICATION_JSON)
.content("teste")
.andExpect(status().is2xxSuccessful());
}
}
#RestController
#RequestMapping(path = "/api/cliente")
public class ClienteController {
#Autowired
private PessoaFisicaService pessoaFisicaService;
#PostMapping(path = "/pessoafisica/post", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> saveClientePessoaFisica(#RequestBody PessoaFisica pessoaFisica) throws Exception {
this.pessoaFisicaService.save(pessoaFisica);
return new ResponseEntity<Void>(HttpStatus.CREATED);
}
}
Your content "teste" is no valid JSON. When I am using your code, I'm getting a JsonParseException complaining about that (By the way, there is a parenthese missing after content("teste") ). Also helpful is using andDo(print()) which will give you the request and response in more detail:
#Test
public void nao_deve_permitir_salvar_cliente_pf_com_nome_cpf_duplicado() throws Exception {
this.mvc.perform(post("/api/cliente/pessoafisica/post")
.contentType(MediaType.APPLICATION_JSON)
.content("teste"))
.andDo(print())
.andExpect(status().is2xxSuccessful());
}
Some things to look for :
Enable logging in your mockmvc
Enable your mockmvc properly
When using spring security, initialise it in mockmvc
When using spring security / CSRF / HTTP POST , pass a csrf in your mockmvc
Enable debug logging
Like this :
logging:
level:
org.springframework.web: DEBUG
org.springframework.security: DEBUG
Working test :
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
#AutoConfigureMockMvc
public class MockMvcTest {
#Autowired
protected ObjectMapper objectMapper;
#Autowired
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void init() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(springSecurity()).build();
}
#Test
public void adminCanCreateOrganization() throws Exception {
this.mockMvc.perform(post("/organizations")
.with(user("admin1").roles("ADMIN"))
.with(csrf())
.contentType(APPLICATION_JSON)
.content(organizationPayload("org1"))
.accept(APPLICATION_JSON))
.andDo(print())
.andExpect(status().isCreated());
}
}

Resources