I'm working with Eureka and I have a Method that uses the DiscoveryClient to obtain the instances of a service and the call this service and retrieve some information like this:
List<ServiceInstance> instances = discoveryClient.getInstances(CSC_APP_NAME);
ServiceInstance serviceInstance = instances.get(0);
String baseUrl = serviceInstance.getUri().toString();
baseUrl = baseUrl + usrEmail + "/services";
ResponseEntity<Service> response = restTemplate.getForEntity(baseUrl, Service.class);
It works, but now I want to make a JUnit test for the method and as I'm not going to have the Eureka working in the JUnit test environment, I think I should mock the discoveryClient, but how should I make this mock? I'm using mockito in the project.
It's correct to mock the discoveryClient in the unit test. Using Junit 5:
public class MyServiceTest {
#InjectMocks
private MyService myService;
#Mock
private DiscoveryClient discoveryClient;
#Mock
private RestTemplate restTemplate;
#BeforeEach
public void initTest() {
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() {
ServiceInstance si = mock(ServiceInstance.class);
when(si.getUri()).thenReturn(URI.create("myUri"));
when(discoveryClient.getInstances(anyString()))
.thenReturn(List.of(si));
myService.myMethod();
}
}
I also mocked the restTemplate, but that is up to you. MyService.myMethod() implementation:
public void myMethod() {
List<ServiceInstance> instances =discoveryClient.getInstances("CSC_APP_NAME");
ServiceInstance serviceInstance = instances.get(0);
String baseUrl = serviceInstance.getUri().toString();
baseUrl = baseUrl + "userEmail" + "/services";
ResponseEntity<Service> response = restTemplate.getForEntity(baseUrl, Service.class);
}
Related
I am trying to write an Integration test where I have an issue in mocking the rest call which is calling outside server using JUnit.
I have added a #Mock and #InjectMock on service
Service looks like this.
#Service
public class BoundaryDeltaService {
private BoundaryDelta getBoundaryDeltaUsingApp() {
List<BoundaryValueInfo> infoFromSource = Arrays.asList(serviceAdapter.readInfoFromApiUsingApp(boundarySet, app, loginUserInfo));
return getBoundaryDeltacompareCurrentBoundaryValuesWithSource(boundarySet, infoFromSource );
}
}
There is another service with has restTemplate call
#Service
public class ServiceAdapter {
public BoundaryValueInfo[] readInfoFromApiUsingApp(){
String loginToken = systemUserLoginService.getSystemUserTokenManual(app, loginUserInfo);
restTemplate = createRestTemplate(boundarySet);
HttpHeaders headers = new HttpHeaders() {{
String authHeader = "Bearer " + loginToken;
set( "Authorization", authHeader );
}};
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<BoundaryValueInfo[]> answerFromApi = restTemplate.exchange(boundarySet.getApiUri(), HttpMethod.GET, request, BoundaryValueInfo[].class);
return getResponseFromApi(answerFromApi);
}
}
And this is the test scenario
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles({"aws", "local"})
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = FlywayConfig.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
public class BoundaryValueDeltaControllerTest {
private static final String API_V1 = "/api/v1/";
#Autowired
TestRestTemplate testRestTemplate;
#Autowired
private BoundaryDeltaService boundaryDeltaService;
#Autowired
private DomainBuilder domainBuilder;
#Autowired
private AppBuilder appBuilder;
#Autowired
private AppAdminBuilder appAdminBuilder;
#Autowired
private BoundaryValueBuilder boundaryValueBuilder;
#Autowired
private BoundarySetBuilder boundarySetBuilder;
#MockBean
private LoginUserProvider loginUserProvider;
#MockBean
private LoginTokenService loginTokenService;
#InjectMocks
private BoundaryServiceAdapter boundaryServiceAdapter;
#Mock
RestTemplate restTemplate;
#LocalServerPort
private int port;
Domain domain;
App app;
BoundarySet boundarySet;
BoundaryValue boundaryValue;
LoginUserInfo loggedInUser;
#Before
public void setUp() {
clear();
domain = domainBuilder.persist();
app = appBuilder.persist(domain);
boundarySet = boundarySetBuilder.persist(domain);
boundaryValue = boundaryValueBuilder.persist(boundarySet);
}
#After
public void tearDown() {
clear();
}
#BeforeClass
public static void setupTestEnv() {
// https://github.com/localstack/localstack/issues/592
}
#Test
public void updateBoundaryValuesFromApi() {
aLoggedInUser(domain.getAuthor().getUsername());
appAdminBuilder.persist(app, domain.getAuthor());
ResponseEntity<BoundaryValueInfo[]> answerFromApi = getBoundaryValueInfos();
HttpHeaders headers = new HttpHeaders() {{
String authHeader = "Bearer 1234";
set( "Authorization", authHeader );
}};
HttpEntity<String> request = new HttpEntity<>(headers);
//when(restTemplate.exchange(boundarySet.getApiUri(), HttpMethod.GET, request, BoundaryValueInfo[].class)).thenReturn(answerFromApi);
when(restTemplate.exchange(ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<BoundaryValueInfo[]>>any())
).thenReturn(answerFromApi);
String url = url(API_V1 + "domains/" + domain.getName() + "/boundarysets/" + boundarySet.getBoundarySetName() + "/app/" + app.getName()+ "/updatefromapi/");
ResponseEntity<String> response = testRestTemplate.exchange(url,HttpMethod.GET, null, String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
}
}
I am calling controller with api and from there it is going into above services which has rest call but not able to mock the actual call.
Can someone guide me here ?
You are not using the TestRestTemplate for the purpose it is intended for.
TestRestTemplate is not an extension of RestTemplate, but rather an alternative that simplifies integration testing and facilitates authentication during tests. It helps in customization of Apache HTTP client, but also it can be used as a wrapper of RestTemplate
Solution:
Approach1:
1) Directly call the exchange method using RestTemplate object.
ResponseEntity<String> response = restTemplate .exchange(url,HttpMethod.GET, null, String.class);
2) Mock the testRestTemplate and do the mock when on the exchange method call for this object.
when(testRestTemplate.exchange(ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<BoundaryValueInfo[]>>any())
).thenReturn(answerFromApi);
I'm new to unit tests and well, I'm struggling to understand how it should be done.
I have some methods with #RequestParam and I'm not sure how to mock this.
It would be great if I had an example I could apply to the other methods.
Could you help me by writing the test method for this one? It would be very useful.
#PutMapping("/player/update-password")
public ResponseEntity<?> updatePlayerPassword(#RequestParam("token") String token, #RequestParam("password") String newPassword) throws URISyntaxException {
String message = bundle.getString("put_player");
log.debug(message, token, newPassword);
PlayerEntity player = playerService.updatePassword(token, newPassword);
return new ResponseEntity<>(PlayerMapper.INSTANCE.mapPlayer(player), HttpStatus.ACCEPTED);
}
Thanks.
You can use #Mock and #InjectMocks annotations. With it you can inject mocks to your controller.
#Mock
PlayerService playerServiceMock;
And use when().then() from Mockito inside test or method with #Before annotation:
when(playerServiceMock.updatePassword(anyString(), anyString())).thenReturn(playerEntity);
The same can be done for bundle.getString("put_player").
Hoping you are using the Mockito. You can try the below code, need to add all imports
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class YourClassNameTest {
#Autowired
MockMvc mockMvc;
#InjectMocks
YourClassName yourClassName;
#Mock
PlayerService playerService;
#Before
public void Setup() {
mockMvc = MockMvcBuilders.standaloneSetup(yourClassName);
}
#Test
public void updatePlayerPasswordTest() throws Exception {
PlayerEntity player = new PlayerEntity();
// set some date if you want
Mockito.when(playerService.updatePassword(anyString(), anyString())).thenReturn(player);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.get("/player/update-password?token=abc&password=test")
.accept(MediaType.APPLICATION_JSON);
mockMvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.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 writing a simple REST client, my service class has one method using
RestTemplate.getForObject()
I would like to practice testing but I don't really know if we should test the class. I also do not know how to test method that does not do much. Should I write any unit tests?
You can test, that request has been sent. For example you have the next service:
#Service
public void QueryService {
private final RestTemplate restTemplate;
#Autowired
public QueryService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public List<Employee> void makeQuery() {
ResponseEntity<List<Employee>> response = restTemplate.getForObject(
"http://localhost:8080/employees",
EmployeeList.class);
return response.getEmployees();
}
}
For the method makeQuery you can write the next unit test:
#RunWith(MockitoJUnitRunner.class)
public class QueryServiceTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private QueryService queryService;
#Test
public void testMakeQueryRequestHasBeenSent() {
List<Employee> result = queryService.makeQuery();
// This string checks that method getForObject has been invoked
verify(restTemplate).getForObject(anyString(), any(Class.class));
}
}
In the future, if you will change makeQuery method and forget to send request using restTemplate, this test will fail.
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);
}
}