Spring Boot Test MockMvc perform post - Not working - spring

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

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(...)
// ...
}

#ControllerAdvice not triggered on unit testing

I need to test #ControllerAdvice methods which are in service layer. But I faced two issues:
ExceptionHandlers not triggered
And even if it would be triggered, I find out that don't now how to test it)
#Slf4j
#ControllerAdvice
public class AppExceptionHandler {
#ExceptionHandler(value = {.class})
public ResponseEntity<Object> handleMyException(MyException ex, WebRequest request) {
ErrorMessage errorMessage = ErrorMessage.builder()
.message(ex.getMessage())
.httpStatus(HttpStatus.BAD_REQUEST)
.time(ZonedDateTime.now())
.build();
return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
}
#RunWith(MockitoJUnitRunner.class)
#RequiredArgsConstructor
public class MyExceptionTest {
private final AppExceptionHandler handler;
#Mock private final MyService service;
#Test
public void test() throws MyException {
when(service.create(any()))
.thenThrow(MyException .class);
}
}
For this purpose, you can write a test for your controller layer with #WebMvcTest as this will create a Spring Test Context for you that contains all #ControllerAdvice.
As your service is throwing this exception, you can mock the service bean with #MockBean and use Mockito to instruct your bean to throw the expected exception.
As I don't know how your controller looks like, the following is a basic example:
#RunWith(SpringRunner.class)
#WebMvcTest(MyController.class)
class PublicControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private MyService myService;
#Test
public void testException() throws Exception {
when(myService.create(any())).thenThrow(new MyException.class);
this.mockMvc
.perform(get("/public"))
.andExpect(status().isBadRequest());
}
}

Spring Boot Server and Client testing. Is it possible to combine them to achieve something like this?

Combining server testing MockMvc, and client testing #RestClientTest. Is this possible or will they always clash with each other?
#AutoConfigureMockMvc
#RestClientTest(BackendApiClient.class)
public class ApiGatewayControllerTest extends ApiTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private MockRestServiceServer mockServer;
#Test
public void get_backend_defs_should_return_200() throws Exception {
mockServer.expect(ExpectedCount.once(), requestTo("/apirepo"))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(loadFileAsString("json/client/get_all.json")));
getJson("/get/backend").andExpect(isOk()).andExpect(
MockMvcResultMatchers.content().json(loadFileAsString("json/controller/get_all.json")));
mockServer.verify();
}
private ResultActions getJson(String path) throws Exception {
return mockMvc.perform(
MockMvcRequestBuilders.get(path).accept(MediaType.APPLICATION_JSON));
}
}
Thank you

JUnit not working in Spring Boot with #Autowired annotation

I have a Spring Boot application in which I'm creating REST web services
using the MVC pattern.
I have a controller, service and DAO class and I use the #Autowired annotation for calling methods of the service and DAO layer.
When I create JUnit tests using mockito, the values are going into the controller but from the controller they are not going to the service class.
Here is the code sample:
#WebAppConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {AppplicationConfiguration.class})
public class ExternalControllerTest {
private MockMvc mockMvc;
#InjectMocks
private MyController myController;
#MockBean
myService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.build();
}
#Test
public void testListCluster() throws Exception {
Input emrInput = new Input();
emrInput.setId("200004773");
emrInput.setName("test");
String expected = "{\"status\":\"Success\",\"message\":\"Success\",\"data\":\"somevalue\"}";
AutomateRestResponse response = new AutomateRestResponse<JsonObject>();
response.setMessage("Success");
response.setStatus("Success");
response.setData("somevalue");
Mockito.when(
externalService.listCluster(emrInput)
).thenReturn(response);
mockMvc.perform(post("/v1/gerData"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("Success")));
verify(externalService, times(1)).listCluster(emrInput);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/v4/listCluster")
.accept(MediaType.APPLICATION_JSON).content(emrInputJosn)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println("response body1" + result.getResponse()
.getContentAsString());
}`
Please help me with this.
It is not clear from your question what you are trying to mock.
Anyway, you should not be able to debug your service/dao that is mocked since what actually executed in the test is the mocked one and not yours.
If you want to test your controller, you can mock your service or dao and define what the response they will return, and then verify that the response you get from your controller is as you expect it to be.
#EnableWebMvc
#SpringBootApplication(scanBasePackages = { "com.yourPackage.external" })
public class YourApplication extends org.springframework.boot.web.support.SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<Application> applicationClass = Application.class;
}
Based on what you have pasted, you can do below things:
if you are using #RunWith(SpringJUnit4ClassRunner.class) [better change to #RunWith(SpringRunner.class)] then use
#MockBean
private MyService externalService;
OR
use #RunWith(MockitoJUnitRunner.class) and
#MockBean
private MyService externalService;
#InjectMocks
private MyController controller = new MyController(externalService);
for details checkout :- testing web in spring boot
#WebAppConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {AppplicationConfiguration.class})
public class ExternalControllerTest {
private MockMvc mockMvc;
#InjectMocks
private MyController myController ;
#MockBean
myService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.build();
}
#Test
public void testListCluster() throws Exception {
Input emrInput = new Input();
emrInput.setId("200004773");
emrInput.setName("test");
String expected = "{\"status\":\"Success\",\"message\":\"Success\",\"data\":\"somevalue\"}";
AutomateRestResponse response = new AutomateRestResponse<JsonObject>();
response.setMessage("Success");
response.setStatus("Success");
response.setData("somevalue");
Mockito.when(
externalService.listCluster(emrInput)
).thenReturn(response);
mockMvc.perform(post("/v1/gerData"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("Success")));
verify(externalService, times(1)).listCluster(emrInput);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/v4/listCluster")
.accept(MediaType.APPLICATION_JSON).content(emrInputJosn)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println("response body1"+ result.getResponse()
.getContentAsString());
}
}

How can I test my SpringBoot RestController using a MockMvc when I rely on a Spring Validator?

In my rest-controller I am validating the input JSON with a custom Spring validator class.
When I now want to write unit test for the controller then I am getting the error that my Validator could not be found...
I am using constructor injecting for the two components in my rest-controller.
#Autowired
public JobController(JobValidator jobValidator, JobService jobService) {
this.jobValidator = jobValidator;
this.jobService = jobService;
}
And here my corresponding Test class.
#RunWith(SpringRunner.class)
#WebMvcTest(JobsController.class)
#AutoConfigureMockMvc
public class MailMonitorJobControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private JobService jobService;
#Test
public void givenJobs_whenGetJobs_thenReturnJsonArray() throws Exception {
Job job = new Job("TEST");
List<Job> allJobs = Arrays.asList(job);
Mockito.when(jobService.getAllJobs()).thenReturn(allJobs);
mockMvc.perform(get("/api/v1/test")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Appreciate any help, hints or suggestions!
So thanks to #pvpkiran! I had to add the JobValidator also as a Mock!
#RunWith(SpringRunner.class)
#WebMvcTest(JobsController.class)
#AutoConfigureMockMvc
public class MailMonitorJobControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private JobService jobService;
#MockBean
private JobValidator jobValidator;
#Test
public void givenJobs_whenGetJobs_thenReturnJsonArray() throws Exception {
Job job = new Job("TEST");
List<Job> allJobs = Arrays.asList(job);
Mockito.when(jobService.getAllJobs()).thenReturn(allJobs);
mockMvc.perform(get("/api/v1/test")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}

Resources