java.lang.AssertionError: Status Expected :200 Actual :500 - spring-boot

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

Related

MockMVC always Null

MockMvc is always null! i also tried other annotations like it is described at other questions but nothing works.
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = HelpPageController.class)
public class HelpPageControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void test() throws Exception {
//other code
ResultActions result = mockMvc.perform(MockMvcRequestBuilders.get("/help/manuals"));
//other code
}
You should add #AutoConfigureMockMvc annotation, so the MockMvc can be injected in your test class.

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

How to inject MockMvc with multiple objects in Spring Boot REST Junit test case

I have a SpringBoot REST API connecting to Oracle DB.
My controller calls BusinessImpl layer and in-turn BusinessImpl calls multiple DAO layers (Controller -> BusinessImpl -> DAO1, DAO2, DAO3)
The below test case works perfectly
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration()
#TestPropertySource("classpath:dev-manifest.yml")
#ContextConfiguration(classes = Application.class)
#ConfigurationProperties(prefix = "env")
#SpringBootTest
public class MyTest
{
private static final String REQUEST_URI = "/v1/registration/accounts/links";
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup()
{
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void testSave()
{
String testInput = "some json input";
mockMvc.perform(post(REQUEST_URI).content(testInput).contentType(contentType))
.andExpect(status().isOk());
}
But I do not want to hit real database during junit test case. So I wrote a mock.
Working Code
#Mock
private SecurityAuditDAO securityAuditDAO;
#InjectMocks
private RegistrationBusinessImpl registrationBusinessImpl;
#Test
public void testSave()
{
when(securityAuditDAO.getState(Mockito.any())).thenReturn("somestring");
SomeRequest someRequest = new SomeRequest();
someRequest.setStatus("SUCCESS");
SomeResponse status = registrationBusinessImpl.createUser(SomeRequest, "127.0.0.1");
}
The above code worked perfectly. In businessImpl class securityAuditDAO.getState returned "somestring". But when I introduced mockMvc.perform it stopped working.
Not Working
#Test
public void testSave()
{
when(securityAuditDAO.getState(Mockito.any())).thenReturn("somestring");
String testInput = "some json input";
mockMvc.perform(post(REQUEST_URI).content(testInput).contentType(contentType))
.andExpect(status().isOk());
}
The above code was still hitting the database. So I realized that I should inject mockMvc with securityAuditDAO so I added the following line
this.mockMvc = MockMvcBuilders.standaloneSetup(securityAuditDAO).build();
Code
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private SecurityAuditDAO securityAuditDAO;
#InjectMocks
private RegistrationBusinessImpl registrationBusinessImpl;
#InjectMocks
RegistrationApiController registrationApiController;
#Before
public void setup()
{
MockitoAnnotations.initMocks(this);
//this.mockMvc = webAppContextSetup(webApplicationContext).build();
this.mockMvc = MockMvcBuilders.standaloneSetup(securityAuditDAO).build();
//this.mockMvc = MockMvcBuilders.standaloneSetup(registrationApiController).build();
//ReflectionTestUtils.setField(mockMvc, "securityAuditDAO", securityAuditDAO);
}
I tried injecting securityAuditDAO. But if I do that, my other autowired instances in BusinessImpl were null.
How to inject securityAuditDAO without affecting others or how to inject both webApplicationContext and securityAuditDAO.
Also tried ReflectionTestUtils.setField but it didn't work as expected.

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

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