I am trying to test a RestTemplate exchange with a response entity in a controller from a rest Service in another application. My Junit test is coming back with a null ResponseEntity. I have tried a couple ways with no luck. First tried using mockito to mock response methods (when...then). Second tried with Exchange matchers. I also tried to mix the two with no luck. Any help would be great. Here is my Controller response I am creating:
ResponseEntity<RestResult<List<SiteMessage>>> response = rest.exchange(getAllMessagesUrl, HttpMethod.GET,
HttpEntity.EMPTY, new ParameterizedTypeReference<RestResult<List<SiteMessage>>>() {
});
Here is my Junit Test:
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest
public class MessageControllerTests {
#InjectMocks
MessageController messageController;
#Mock
RestTemplate restTemplate;
#Mock
SiteMessageService serviceMock;
#Mock
ResponseEntity<RestResult<List<SiteMessage>>> response;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(messageController).build();
}
#Test
public void testListPage() throws Exception {
RestResult<List<SiteMessage>> result = new RestResult<>();
result.setMessage("success");
SiteMessage message1 = new SiteMessage();
SiteMessage message2 = new SiteMessage();
message1.setId("ldsf030j2ldjs");
message2.setId("ldsf0432234s");
List<SiteMessage> messageList = new ArrayList<>();
messageList.add(message1);
messageList.add(message2);
result.setResults(messageList);
when(response.getBody()).thenReturn(result);
when(response.getStatusCode()).thenReturn(HttpStatus.NOT_FOUND);
when(restTemplate.exchange(
Matchers.any(URI.class),
Matchers.eq(HttpMethod.GET),
Matchers.any(),
Matchers.<ParameterizedTypeReference<RestResult<List<SiteMessage>>>>any())
).thenReturn(response);
mockMvc.perform(get("/message/list")).andExpect(status().isOk()).andExpect(view().name("message/list"));
}
}
I am trying to return a response with a body containing a RestResult object, which has a list of messages and a message
Related
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());
I am trying to test my REST endpoints using RestAssured with mocking some of the service/repositories in the controller.
this is my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {VedicaConfig.class})
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class RESTTest {
#LocalServerPort
private int port;
#Autowired
private MockMvc mvc;
#Mock
MetaVersionDAO metaVersionDAO;
#InjectMocks
DocCtrl docCtrl;
#Before
public void contextLoads() {
RestAssured.port = port;
assertThat(mvc).isNotNull();
// this must be called for the #Mock annotations above to be processed.
MockitoAnnotations.initMocks(this);
RestAssuredMockMvc.standaloneSetup(MockMvcBuilders.standaloneSetup(docCtrl));
}
#Test
public void shouldGetThumbnail() {
String ver = "1.0";
String uuid = "124-wqer-365-asdf";
when(metaVersionDAO.getMetaByVersionUUID(ver, uuid)).thenReturn(new DocVersion());
given()
.when()
.param("uuid", uuid)
.param("versionVed", ver)
.get(CTX_BASE + "/thumbnail")
.then()
.log().ifValidationFails()
.statusCode(OK.value())
.contentType(ContentType.BINARY);
}
}
now, the REST endpoint itself is being hit correctly with supplied parameters. this endpoint has DocCtrl injected which uses metaVersionDAO instance in turn:
public RawDocument getDocThumbnail(String uuid, String versionVed) throws Exception {
DocVersion docVersion = metaVersionDAO.getMetaByVersionUUID(versionVed, uuid);
InputStream inputStream = okmWebSrv.getOkmService().getContentByVersion(uuid, versionVed);
String dataType = docVersion.getMetadata().getAdditionals().get(Vedantas.CONTENT_TYPE);
ByteArrayInputStream bais = new ByteArrayInputStream(createPDFThumbnail(dataType, inputStream));
RawDocument rawDocument = new RawDocument(bais, "qwer");
return rawDocument;
}
as you can see, I have tried to mock metaVersionDAO at the top of the #Test method so I expected it to return new DocVersion() as I set it to, but in this DAO the actual code is being called and it fails on entityManager which is null.
My question is why metaVersionDAO.getMetaByVersionUUID doesn't return my mocked object and what should I do to make it so?
spring-mock-mvc: 3.3.0
spring-boot: 2.1.2.RELEASE
Thanks!
solved by changing #Mock for #MockBean.
so it is:
#MockBean
MetaVersionDAO metaVersionDAO;
everything else remains the same as in the post and it uses mocked instance.
I am attempting to write a unit test for a generic service class like the following:
public class ApiService{
private RestTemplate restTemplate;
private ServiceDao serviceDao;
#Autowired
public ApiService(RestTemplate restTemplate, ServiceDao serviceDao) {
this.restTemplate = restTemplate;
this.serviceDao = serviceDao;
}
public ResponseEntity getObject(ObjectRequest request) {
// Service logic here
}
public ResponseEntity postObject(CreateObjectRequest request) {
// Service logic here
}
}
But am struggling with how to mock the restTemplate in the constructor of my service class such that when the test runs, data is not persisted.. I've looked into Mockito though don't see many examples or documentation regarding Mockito + TestNG in this context. Any help would be appreciated
First of all - if possible inject RestOperations in your service instead of RestTemplate. Then you will be able easily mock its behavior (note: RestTemplate implements RestOperations).
If using RestOperations is not possible - you can do something this:
RestTemplate myTemplate = Mockito.spy(new RestTemplate());
String expectedOutput = "hello mock";
String inputUrl = "https://stackoverflow.com/questions/53872148/unit-test-service-class-with-mocks-using-testng";
Mockito.doReturn(expectedOutput).when(myTemplate).getForObject(inputUrl, String.class);
String result = myTemplate.getForObject(inputUrl, String.class);
Assert.assertEquals(expectedOutput, result);
I've actually constructed a method using Mockito as follows... there might be a more elegant solution so I would be interested to see:
public class ServiceTest {
#BeforeMethod(groups="serviceTest")
public void beforeMethod() {
MockitoAnnotations.initMocks(this);
}
#Test(groups="serviceTest")
public void testGetService_returns200() {
when(serviceDao.getService(any(String.class), any(RestTemplate.class), any(HttpHeaders.class))).thenReturn(new ResponseEntity(new Object(), HttpStatus.OK));
ObjectRequest request = new ObjectRequest();
// set request values
ResponseEntity testResponse = apiService.getObject(request);
}
}
I am trying to mock RestTemplate but I when debugging I see the error bellow, which produces a null pointer:
Method threw 'org.mockito.exceptions.misusing.UnfinishedStubbingException' exception. Cannot evaluate org.springframework.http.ResponseEntity$$EnhancerByMockitoWithCGLIB$$3c63496d.toString()
This is the line of code that I am trying to test :
ResponseEntity<EmailEntity[]> response =
restTemplate.exchange(apiURI, HttpMethod.GET, entity, EmailEntity[].class);
EmailEntity[] partialEmailEntity = response.getBody();
response.getBody() returns a null.
This is a piece of code in my test :
#RunWith(MockitoJUnitRunner.class)
public class EmailItemReaderTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private EmailItemReader reader;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
...
...
ResponseEntity<EmailEntity> mockEntity = Mockito.spy(new ResponseEntity(mockObject, HttpStatus.OK));
doReturn(mockEntity).when(restTemplate).exchange(
Mockito.any(URI.class),
Mockito.any(HttpMethod.class),
Mockito.any(HttpEntity.class),
EmailEntity[].class);
reader.read();
While trying to get my PUT MockMvc test to work, I found that JSON was not supported. Using an answer from this thread:
Configure MappingJacksonHttpMessageConverter
I was able to resolve this by extending the WebMvcConfigurationSupport class. However, when I use this override, it appears as though the ModelAndView data returned in my GET tests is now NULL. I know I can get the response data using this:
String content = result.getResponse().getContentAsString();
But, does anyone have an explanation for why the ModelAndView data is NULL?
Here is my MockMVC test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("test-rest-context.xml")
public class AccountControllerTest {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Before
public void setUp() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
#Test
public void findCustomerByID() throws Exception {
MvcResult result = mockMvc.perform(get("/api/account/customers/{customerID}", "123").accept(contentType)
.param("fields", "id", "email", "userName")
.contentType(contentType))
.andExpect(status().isOk())
.andReturn();
ModelAndView mav = result.getModelAndView();
// mav is NULL here after I extend WebMvcConfigurationSupport class.
}
}