Mock Spring Controller for unit testing - java

I'm trying to test a rest call that is a part of an mvc controller.
My unit test is currently returning a 404 error code, instead of a 200 status code, which would determine that the request was sent successfully.
Here's the signature of my method that I'm trying to test:
#PreAuthorize("hasRole('ROLE_SSL_USER')")
#PostMapping(value = "/employee", consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Object> postEmployee(HttpEntity<String> httpEntity, #RequestHeader("DB-Client-Id") String clientId,
#RequestHeader("X-Forwarded-Client-Dn") String dn) throws IOException, ValidationException {}
Here's my unit test class:
public class ControllerTest {
#InjectMocks
private Controller aController;
private MockMvc mockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(aController).build();
}
#Test
public void PostEmpTest() {
try {
this.mockMvc.perform(post("/employee")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Am I missing something from my perform() call that is resulting in the 404 bad request code?

I use for controller tests code like this
#RunWith(SpringRunner.class)
#WebMvcTest(Controller.class)
#AutoConfigureWebClient
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void entityTypes() throws Exception {
String json = "...";
mockMvc.perform(
post("URL")
.contentType(APPLICATION_JSON_UTF8)
.content(json))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_UTF8))
;
}
}
Try it - I hope, it will help.
PS: also, I'm not sure, but it looks like you need add #RequestBody to your controller method declaration:
public ResponseEntity<Object> postEmployee(
#RequestBody HttpEntity<String> httpEntity,
#RequestHeader("DB-Client-Id") String clientId,
#RequestHeader("X-Forwarded-Client-Dn") String dn) throws IOException, ValidationException {}

Related

Unable to test controller using MockMVC

I am trying to test my controller using MockMvc. While performing this mockMvc.perform(requestBuilder).andReturn(); It doesn't hit my API. So I am getting this response.
org.junit.ComparisonFailure: The Mock Response object should be same
Expected :dGVzdDEyMw==
Actual :
This is my controller class
public class AddLibClientRestController
{
#Autowired
private AddAPIService addAPIService;
#PostMapping(value = "/v1/add")
public String encrypt (#RequestParam final String plainText) throws GeneralSecurityException
{
return addAPIService.add(plainText);
}
}
This is my test class
public class AddLibClientRestControllerTest
{
/** The instance of EncryptionAPIService. */
#MockBean
private AddAPIService mockAddAPIService;
#Autowired
private MockMvc mockMvc;
#Test
public void testEncryptWithMockObjectReturned () throws Exception
{
final MockHttpServletRequestBuilder requestBuilder =
post("/v1/add")
.param("plainText", "test123");
when(mockAddAPIService.add(anyString())).thenReturn("dGVzdDEyMw==");
final MvcResult result = mockMvc.perform(requestBuilder).andReturn();
assertEquals("The Mock Response object should be same", "dGVzdDEyMw==",
result.getResponse().getContentAsString());
}
}
Please suggest something, what i am doing wrong here in this. Thanks

Mocked Rest template is returning a null response

I am new to JUnit5 and Mockito framework in springboot. Here I am trying to mock the RestTemplate and return a 200 status with a string response. But I am getting a null response and the function throws a Null Pointer Exception. Is there any mistake in the way I am mocking the rest template?
Service
public class Abc {
#Autowired
RestTemplate template;
#Value("${ser.url}")
String url;
void validate(String val){
ResponseEntity<String> response;
try{
response = template.postForEntity(url, HTTP_ENTITY, String.class);
} catch(Exception ex ){
.....
}
sysout(response); //Prints Null
String res = response.getBody(); //Null Pointer exception
}
}
Testing
class ServiceTest {
#InjectMocks
Abc abc;
#Mock
RestTemplate template;
#BeforeEach
void setup(){
MockitoAnnotations.init(this);
}
#Test
void testIt(){
when(template.postForEntity(anyString(), any(), ArgumentMatchers.<Class<String>>any())).
thenReturn(new ResponseEntity<String>("value",HttpStatus.OK));
abc.validate("abc");
}
}
After long time experiments in the past I have realized that #InjectMocks sometimes works not as expected. So now I make use of #MockBean instead. This code works:
#Service
public class Abc {
#Autowired
RestTemplate template;
#Value("${ser.url}")
String url;
void validate(String val){
ResponseEntity<String> response = null;
try{
response = template.postForEntity(url, new HttpEntity<>(""),
String.class);
} catch(Exception ex ){
ex.printStackTrace();
}
System.out.println(response); //Prints Null
String res = response.getBody(); //Null Pointer exception
}
}
#SpringBootTest
class AbcTest {
#Autowired
Abc abc;
#MockBean
RestTemplate template;
#Test
void testIt(){
when(template.postForEntity(anyString(), any(), ArgumentMatchers.<Class<String>>any())).
thenReturn(new ResponseEntity<String>("value", HttpStatus.OK));
abc.validate("abc");
}
}

When try to test post() rest endpoint see: json can not be null or empty

If I try to test the post() endpoint, I see:
java.lang.AssertionError: No value at JSON path "$.firstName"
Caused by: java.lang.IllegalArgumentException: json can not be null or empty
But with the test for the get() all work fine.
And in the postTest() the result for status is correct.
Where is my mistaker?
Is it correct way to test the rest controller in this style?
#RunWith(MockitoJUnitRunner.Silent.class)
public class Temp {
private final Employee successfullyRegisteredEmployee = new Employee(2L, "Iven");
private final Employee employeeGetById = new Employee(2L, "Iven");
#Mock
private EmployeeServiceImpl serviceMock;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(new EmployeeControllerImpl( serviceMock))
.build();
}
#Test
public void getTest() throws Exception {
when(serviceMock.getEmployee(2L)).thenReturn(employeeGetById);
mockMvc.perform(get("/employee/get/2"))
.andExpect(status().is(200))
.andExpect(content().json(("{'firstName':'Iven'}")));
verify(serviceMock).getEmployee(2L);
}
#Test
public void postTest() throws Exception {
String json = "{\n" +
" \"firstName\": \"Iven\"\n"
"}";
when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);
mockMvc.perform( MockMvcRequestBuilders
.post("/employee/register")
.content(json)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(201))
.andExpect(jsonPath("$.firstName", Matchers.is("Iven")));
}
}
#RestController
#RequestMapping("/employee")
public class EmployeeControllerImpl implements EmployeeController {
private final EmployeeService service;
public EmployeeControllerImpl(EmployeeService service) {
this.service = service;
}
#PostMapping(path = "/register",
consumes = "application/json",
produces = "application/json"
)
public ResponseEntity<Employee> registerEmployee(#Valid #RequestBody Employee employee) {
Employee registeredEmployee = service.register(employee);
return ResponseEntity.status(201).body(registeredEmployee);
}
}
Seems like problem could be with when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);.
Did you try to have breakpoint on return ResponseEntity.status(201).body(registeredEmployee); to check if registeredEmployee is actually filled?
If it's empty then try replacing mock with when(serviceMock.register(any())).thenReturn(successfullyRegisteredEmployee); and if it works that means either equals() method is not overridden for Employee or comparison just fails.

Mocking completeExceptionally with RestAssured (spring-mock-mvc) call to Controller (in Java) [duplicate]

I'm developing a REST API with Spring Boot.
I have a controller to create a new user, that responds with 201 (CREATED) when the user is created. The response has no body content.
Using Postman, or any browser, I got a 201 response.
But when I try with unit test (Mockito), the response is 200.
Here is my code:
Controller:
public CompletableFuture<ResponseEntity<Void>> registerNewUser(
#RequestBody #Valid RegisterUserDto newUser
) throws ExecutionException, InterruptedException {
// user service return a completable future void
return userService.registerNewUser(newUser).thenApply(u -> new ResponseEntity<>(u, HttpStatus.CREATED));
}
The user service returns a completable future void when the register process is completed.
#Async
CompletableFuture<Void> registerNewUser(NewUserDto newUserDto) throws ExecutionException, InterruptedException;
Then, in my unit test, I have the following code:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class UsersControllerTest {
#Autowired
private MockMvc mvc;
#Mock
private UsersService userService;
#InjectMocks
private UsersControllers usersController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
this.mvc = MockMvcBuilders.standaloneSetup(usersController).build();
}
#Test
public void mustCreateANewUser() throws Exception {
NewUserDto userMock = new NewUserDto("firstname", "lastname", "login", "password");
when(userService.registerNewUser(any(NewUserDto.class)))
.thenReturn(CompletableFuture.completedFuture(null));
mvc.perform(post("/api/users/new")
.content(TestHelpers.convertToJson(userMock))
.contentType(TestHelpers.getJsonMediaType()))
.andExpect(status().isCreated());
}
}
TestHelpers.convertToJson and TestHelpers.getJsonMediaType are static methods.
public static MediaType getJsonMediaType() {
return new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
}
public static String convertToJson(Object o) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(o);
}
I do not understand why the response code was 200 on unit test. In any part of my controller, service, or controller advice I have a response 200 OK.
The problem was because my controller and service are async, so my unit test it's not waiting for the correct response.
Changed my unit test to:
MvcResult result = mvc.perform(post("/api/users/new")
.content(TestHelpers.convertToJson(registroMock))
.contentType(TestHelpers.getJsonMediaType()))
.andReturn();
mvc.perform(asyncDispatch(result))
.andExpect(status().isCreated());

java.lang.AssertionError: Status expected:<200> but was:<404> in Junit test

I want to create JUnit test for Rest api and generate api doc. I want to test this code:
Rest controller
#RestController
#RequestMapping("/transactions")
public class PaymentTransactionsController {
#Autowired
private PaymentTransactionRepository transactionRepository;
#GetMapping("{id}")
public ResponseEntity<?> get(#PathVariable String id) {
return transactionRepository
.findById(Integer.parseInt(id))
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.orElseGet(() -> notFound().build());
}
}
Repository interface
public interface PaymentTransactionRepository extends CrudRepository<PaymentTransactions, Integer>, JpaSpecificationExecutor<PaymentTransactions> {
Optional<PaymentTransactions> findById(Integer id);
}
I tried to implement this JUnit5 test with mockito:
#ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
#SpringBootTest(classes = PaymentTransactionsController.class)
#WebAppConfiguration
public class PaymentTransactionRepositoryIntegrationTest {
.....
private MockMvc mockMvc;
#MockBean
private PaymentTransactionRepository transactionRepository;
#BeforeEach
void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
PaymentTransactionRepository processor = Mockito.mock(PaymentTransactionRepository.class);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
.build();
}
#Test
public void testNotNull() {
assertNotNull(target);
}
#Test
public void testFindByIdFound() {
Optional<PaymentTransactions> res = target.findById(Integer.parseInt("1"));
// assertTrue(res.isPresent());
}
#Test
public void indexExample() throws Exception {
this.mockMvc.perform(get("/transactions").param("id", "1"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/xml;charset=UTF-8"))
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
}
}
I get error:
java.lang.AssertionError: Status expected:<200> but was:<404>
What his the proper way to to make GET request to the above code?
Probably I need to add response OK when message is send back?
hi in my case i needed #MockBean of controller and all services that is was autowireing ;)
Instead of #PostMapping and #GetMapping which caused same problem while #RequestMapping in controller helped
It's a path variable, so instead of using param value, please use path variable.
For MvcResult import, you can import org.springframework.test.web.servlet
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
...
given(target.findById(anyInt())).willReturn(Optional.of(new PaymentTransactions(1))).andReturn();
MvcResult result = this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8")).andReturn();
String content = result.getResponse().getContentAsString();
this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8"))
.andExpect(status().isOk())
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
Can you try this..
public class PaymentTransactionsControllerTest {
private MockMvc mvc;
#InjectMocks
PaymentTransactionsController paymentTransactionsController;
#MockBean
private PaymentTransactionRepository processor;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(paymentTransactionsController).build();
}
#Test
public void indexExample() throws Exception {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/transactions/{id}", 1))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
Assert.assertNotNull(result.getResponse().getContentAsString());
}
}

Categories

Resources