The test code
#Mock
private RestTemplate restTemplate;
#InjectMocks
private ServiceClient client;
#Test
public void getDocument() throws IOException {
String fileExtension = "fileextension";
String host = "docserverurl";
String path = "path";
String content = "content";
client = new ServiceClient(restTemplate, host, fileExtension);
when(restTemplate.getForEntity(any(), any()))
.thenReturn(new ResponseEntity(content, HttpStatus.OK));
assertEquals(content, new String(client.getDocument(path)));
}
and the code under test
public byte[] getDocument(String path) throws IOException {
path = suffixWithExtension(path);
return restTemplate.getForEntity(docServiceHost + DOC_SERVICE_API_VERSION_DEFAULT + DOCUMENT + path, byte[].class).getBody();
}
For some reason, I'm running into an issue where when the getForEntity function is called in the function under test , it returns null instead of the mocked response.
Try this. This should work.
byte[] content = "content".getBytes();
when(restTemplate.getForEntity(anyString(), any()))
.thenReturn(new ResponseEntity(content, HttpStatus.OK));
final byte[] sds = someClass.getDocument("sd");
assertEquals(new String(content), new String(sds));
Some tips. If you are doing this
client = new ServiceClient(restTemplate, host, fileExtension);
you do not need #InjectMocks. It is redundant. It is a best practice to use Constructor Injections and not use Field Injections and #InjectMocks.
I hope you are Mocks are initialized. This is done with
MockitoAnnotations.initMocks(this);
This is also done via some Runner classes(If you are using any)
Related
I am unable to get the mocked response from Feign Client. I provide below the code.
In the service class, it has been written like this.
public String getInfo(HttpServletRequest request, String id, String type) {
.... other code .....
try {
statusAsJsonString = myFeignClient.getStatus(cookie, id, type);
System.out.println("statusAsJsonString--------->"+statusAsJsonString);
ObjectNode node = new ObjectMapper().readValue(statusAsJsonString, ObjectNode.class);
if (node.has(CommonConstants.STATUS)) {
statusValue = node.get(CommonConstants.STATUS).asText();
}
} catch (FeignException fe) {
byte[] contents = fe.content();
String jsonContents = null;
if(contents != null) {
jsonContents = new String(contents);
}
statusValue = getErrorParsedStatusValue(jsonContents);
} catch (Exception ex) {
ex.printStackTrace();
}
log.debug("status: " + statusValue);
return statusValue;
}
In the unit test, I am trying to write in the following manner.
String responseBody = "[]";
when(myFeignClient.getStatus("cookievalue", "id", "SOme-Value")).thenReturn(responseBody);
I have also used, WireMock to achieve it.
wireMockServer.stubFor(WireMock.get("/rest/v1/somna/{id}/phase").withRequestBody(WireMock.equalToJson("{ \"name\": \"Phone\", \"initialStock\": 3}"))
.willReturn(WireMock.okJson(responseBody)));
The following piece of code is never covered and executed.
statusAsJsonString = myFeignClient.getStatus(cookie, id, type);
System.out.println("statusAsJsonString--------->"+statusAsJsonString);
Also the invocation of Feign client is inside a service method, first want to get the mocked result of that Feign client.
PLease help me.
I provide below my Feign CLient
#FeignClient(name = CommonConstants.FEIGN_CLIENT_NAME, url = "${feign.service.url}", primary = false)
public interface MyFeignClient {
#GetMapping(value = "/rest/v1/project/{id}/phaseName")
String getStatus(#RequestHeader("Cookie") String cookie,
#PathVariable("id") Stringid, #RequestParam("type") String type);
}
In my test class, I have added the followings.
#Autowired
private MyServiceImpl readyService = new MyServiceImpl();
#Mock
private MyFeignClient myFeignClient;
#ClassRule
public static WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().port(8088));
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
httpServletRequest = Mockito.mock(HttpServletRequest.class);
ReflectionTestUtils.setField(someService, "cookieName", "cookieName");
wireMockServer.start();
}
I'm new to testing and Mockito. However, not so new in working Spring.
I have a service layer implementation of exportResource(String id, String fileType, Class resourceClass) throws MyCustomEx1, MyCustomEx2. My assignment is to create a unit test with Mockito for exportResource() which is downloading a file directly from browser or throws exception if for some reason reaching to ResponseEntity return statement is not successfull.
Here is a rough overview of a service layer class where exportResource() is living;
#Service
#AllArgsConstructor
public class ExportImportServiceImpl implements ExportImportService {
private final FhirRepository fhirRepository;
private final CtsConfig ctsConfig;
#Override
public ResponseEntity<byte[]> exportResource(String id, String fileType, Class resourceClass) throws throws MyCustomEx1, MyCustomEx2 {
if (fileType == null ) throw new MyCustomEx1();
Bundle bundle = (Bundle) fhirRepository.resourcesWithCriterion(resourceClass, DaoConstants.ID, null).get();
if (bundle != null && bundle.hasEntry()) {
Optional<Bundle.BundleEntryComponent> resource =
bundle.getEntry()
.stream()
.filter(filter -> resourceClass.isInstance(filter.getResource()))
.findFirst();
if (resource.isPresent()) {
IBaseResource castedResource = (IBaseResource) resourceClass.cast(resource.get().getResource());
IParser parser = null;
MediaType mt = null;
if (fileType.equalsIgnoreCase("json")){
mt = MediaType.APPLICATION_JSON;
parser = fhirRepository.jsonParser();
} else if (fileType.equalsIgnoreCase("xml")){
mt = MediaType.APPLICATION_XML;
parser = fhirRepository.xmlParser();
} else throw new MyCustomEx1();
parser.setPrettyPrint(true);
var serializedResource = parser.encodeResourceToString(castedResource);
return ResponseEntity
.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,"attachment;" + "filename=" + resourceClass.getSimpleName() + "-" + castedResource.getId() + "." + fileType)
.contentType(mt)
.contentLength(serializedResource.getBytes(StandardCharsets.UTF_8).length)
.body(serializedResource.getBytes(StandardCharsets.UTF_8));
}
}
throw new MyCustomEx2();
}
//other implementations here...
}
I do understand (by wastching some tutorials etc) that we can use Mockito to mock external services/repositories, to verify if some method is getting called, to mock some return values etc. But I'm confused about if-else parts in my business logic-code. Namely, the part:
if (bundle != null && bundle.hasEntry()) {
Optional<Bundle.BundleEntryComponent> resource =
bundle.getEntry()
.stream()
.filter(filter -> resourceClass.isInstance(filter.getResource()))
.findFirst();
if (resource.isPresent()) {
IBaseResource castedResource = (IBaseResource) resourceClass.cast(resource.get().getResource());
IParser parser = null;
MediaType mt = null;
if (fileType.equalsIgnoreCase("json")){
mt = MediaType.APPLICATION_JSON;
parser = fhirRepository.jsonParser();
} else if (fileType.equalsIgnoreCase("xml")){
mt = MediaType.APPLICATION_XML;
parser = fhirRepository.xmlParser();
} else throw new ByException(ByErrorCode.ERR_BY_1013);
parser.setPrettyPrint(true);
var serializedResource = parser.encodeResourceToString(castedResource);
I don't understand how to write test to handle if-else part. I mean, isn't too simple to test something like that?
Here is what I (sadly) got:
#Test
void exportCodeSystem() throws Exception {
String id = "32";
verify(this.fhirRepository.resourcesWithCriterion(ValueSet.class, DaoConstants.ID, null));
Mockito.when(
controller.exportCodeSystem(Mockito.anyString(),Mockito.anyString())
).thenReturn(ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).build());
RequestBuilder request = MockMvcRequestBuilders.get("/url-to-controller")
.param("id","32")
.param("file-type", "json");
MvcResult result = mockMvc.perform(request).andReturn();
Assertions.assertFalse(result.getResponse().getStatus() == 200);
}
This throws some error. But that is not important as to how to write meaningful unit test in this case? Or even better, how to write code which can be easily unit-tested?
UPDATE 1
This is how my test looks now:
#Test
void exportCodeSystem() throws Exception {
CompletableFuture<Bundle> completedFuture = CompletableFuture.completedFuture(this.codeSystemBundle);
Mockito.when(this.fhirRepository.resourcesWithCriterion(ArgumentMatchers.<Class<CodeSystem>>any(),
ArgumentMatchers.<ICriterion<? extends IParam>>any(),
eq(null)))
.thenReturn(completedFuture);
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.
get("/code-system/export")
.param("id", "32").param("file-type", "json"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType("application/json")).andReturn();
Assertions.assertEquals(result.getResponse().getStatus(), HttpStatus.OK.value());
}
I keep getting NPE on the line where MvcResult result .. is. What I want to achive with test? I don't know to be honest. I'm trying to test in a some meaningful way, but I don't think I understand how to achieve that.
This is how controller looks like:
#AllArgsConstructor
#RestController
#RequestMapping("/code-system")
public class CodeSystemController {
private final ExportImportService exportImportService;
#GetMapping("/export")
public boolean exportCodeSystem(#RequestParam("id") String id, #RequestParam("file-type") String fileType) throws IOException, ByException{
return this.exportImportService.exportResource(id, fileType, CodeSystem.class);
}
}
What do you want to test? Would your test be unit test or integration test? Which bean do you want to unit test - controller or the service?
If you want to test the controller via mockMvc you can do this:
#Autowired
private MockMvc mockMvc;
#Autowired
ExportImportService exportImportService;
#Test
public void yourTest() throws Exception {
byte[] expectedBytes = ...;
when(exportImportService.exportResource(id, fileType, CodeSystem.class)).thenReturn(ResourceEntity.ok(expectedBytes ));
mockMvc.perform(post("/code-system/export").param("id", "id").param("file-type", "json")).andExpect(content().bytes(expectedBytes ));
verify(exportImportService).exportResource("id", "json", CodeSystem.class);
}
Or if you want to write an integration test you should mock the repo instead of the service:
#MockBean
FhirRepository fhirRepository
#MockBean // or #Mock, #Spy, #SpyBean depends on your fhirRepository implementation.
IParser parser;
#Test
public void yourTest() throws Exception {
byte[] expectedBytes = ...;
Bundle bundle = ...;
when(fhirRepository.resourcesWithCriterion(Mockito.any(), Mockito.any(), Mockito.any()).thenReturn(bundle)
when(fhirRepository.jsonParser()).thenReturn(parser);
when(parser.encodeResourceToString(Mockito.any())).thenReturn(new String(expectedBytes));
mockMvc.perform(post("/code-system/export").param("id", "id").param("file-type", "json")).andExpect(content().bytes(expectedBytes));
}
I am trying to write a unit test for the below method , where it is invoking the Lambda.
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.services.lambda.model.InvokeRequest;
import software.amazon.awssdk.services.lambda.model.InvokeResponse;
public class RoutingService {
private LambdaClient lambdaClient;
private String env;
private String region;
public RoutingService(){
this.env = System.getenv(ENVIRONMENT);
this.region = System.getenv(REGION);
lambdaClient = LambdaClient.builder().build();
}
public RoutingResponse invokeLambda(InvokeLambda request) throws IOException {
RoutingResponse invokeResponse = new RoutingResponse();
String payload = createPayload(request); // Some utility method
String routingURI = getRoutingURI() ; // Another utility method
SDKBytes payloadBytes = SdkBytes.fromUtf8String(payload);
InvokeRequest invokeRequest = InvokeRequest.builder()
.functionName(routingUri)
.payload(payloadBytes)
.invocationType(INVOCATION_TYPE) // INVOCATION_TYPE is caonstant = RequestResponse
.build();
try{
InvokeResponse result;
result = lambdaClient.invoke(invokeRequest); // Was trying to Mock this
String resultString = result.payload().asUtf8String();
invokeResponse = new ObjectMapper().readValue(resultString, RoutingResponse.class);
}catch(AWSServiceExceptuion ex) {
logger.error(new ErrorEvent(ex.awsErrorDetails.errorMessage(), ex.getMessage(), routingUri));
invokeResponse.setStatusCode(ex.statusCode());
invokeResponse.setBody(ex.getMessage());
}
return response;
}
I am trying to write unit test case for this method as below (Mocking the LambdaClient) .
But still it is trying to call the invoke method of Lambda Client.
Means Mocking is not working properly .
public class RoutingServiceTest {
#Mock
private LambdaClient lambdaClient;
#BeforeEach
void setup(){
MockitoAnnotations.initMocks(this);
}
#Test
void invokeLambda() throws IOException, JSONException {
Map<String,String> queryStringParameters = new HashMap<>();
queryStringParameters.put("test","GOOG");
String[] cookies = {"cookiea", "cookieb"};
Map<String,String> headers = new HashMap<>();
headers.put("header1","valuex");
headers.put("header2","valuey");
InvokeLambda fakeRequest = new InvokeLambda.InvokeLambdaBuilder()
.cdnToken("cdn-token").applicationName("eaf-4137-demo")
.service("quote").method("GET")
.path("QuoteService/getQuote")
.queryString(queryStringParameters)
.headers(headers)
.cookies(cookies)
.body("body")
.requestId("request-id")
.build();
InvokeResponse fakeResponse = InvokeResponse.builder().build(); // This class belongs to AWS library
Mockito.when(lambdaClient.invoke(Mockito.any(InvokeRequest.class))).thenReturn(fakeResponse); // This is not working correctly ..
RoutingService routingService = new RoutingService();
RoutingResponse response = routingService.invokeLambda(fakeRequest);
Assertions.assertTrue(response.getStatusCode()==200);
}
}
When I run this test , an Exception is thrown in the try{} block of 'RoutingService' class , because we are passing a dummy "cdn token"
in fakeResponse.
Ideally , it should not invoke the lambda as we are Mocking it.
Please suggest what am I doing wrong here ?
How to correct this ?
You don't have your lambdaClient mock in your instance of RoutingService. In dead your mock is created in your test setup but you create a new instance of RoutingService that will create its own instance of lambdaClient not the mock you created in your test.
I suggest to update your RoutingService to allow constructor dependency injection:
public RoutingService(final LambdaClient lambdaClient){
this.env = System.getenv(ENVIRONMENT);
this.region = System.getenv(REGION);
this.lambdaClient = lambdaClient;
}
And test like:
RoutingService routingService = new RoutingService(lambdaClient);
RoutingResponse response = routingService.invokeLambda(fakeRequest);
I am trying to mock a getStatusCode using mockito. but I am unable to mock getStatusCode using mockito
public class Client {
private ApiClient adminApiClient;
private UserApi listuserApi;
public Client(String Url) {
this.adminApiClient = new ApiClient().setBasePath(Url + "/admin/");
this.listuserApi = new UserApi(this.adminApiClient);
}
public String getUser() {
String errorMessage = null;
try {
ApiResponse<User> response =
listuserApi.listVpcUsersWithHttpInfo("string");
if (response.getStatusCode() != 200) {
errorMessage = "Agent returned response code " +
response.getStatusCode();
}
} catch (Exception ex) {
errorMessage = "error"
}
return errorMessage;
}
I have tried this approach:
url = "www.google.com";
Client client = new Client(url);
Client client1 = Mockito.spy(client);
ApiClient adminApiClient = new ApiClient().setBasePath(url + "/zsaadmin/");
UserApi listuserApi = new UserApi(adminApiClient);
UserApi listuserApi1 = Mockito.spy(listuserApi);
ApiResponse<User> response = Mockito.mock(ApiResponse.class);
Mockito.when(listuserApi1.listVpcUsersWithHttpInfo("string")).thenReturn(response);
//Mocking line
Mockito.when(response.getStatusCode()).thenReturn(200);
String errorMessage = client1.getUserApi();
//Since response.getStatusCode is 200, the errorMeassage should be null
assertEquals(null,errorMessage);
But 200 is not returned which means mocking line is not executed. errorMessage still depends on the url passed. But it should return null as response code is mocked as 200
Could someone tell where my I am doing wrong?
It is because you haven't set your mock into the instance of client1. As this is more like design problem of your class Client, you have to use reflection to set the mock to that private variable. You can use FieldSetter in mockito to set that value before you call client1.getUserApi()
FieldSetter.setField(client1,
client1.getClass().getDeclaredField("listuserApi"), listuserApi1);
I'm trying to create a test where I have to mock a method inside the class that I want to test. But it keeps calling the real method, but I want mock it.
The method that I want to mock is
extractSecretValue(String path)
I know it's not mocking the method because there is a "println", and it's printing.
What am I doing wrong?
I'm using JUnit 5
The class that I want to test:
#Configuration
public class RestTemplateConfig {
#Value("${******}")
private String keystore;
#Value("${******}")
private String identificador;
#Value("${******}")
private String token;
#Bean
public RestTemplate restTemplate() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext context = null;
context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, null);
List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader("Authorization", "Bearer " + extractSecretValue(token)));
CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(context).setDefaultHeaders(headers)
.build();
HttpComponentsClientHttpRequestFactory hcchr = new HttpComponentsClientHttpRequestFactory(httpClient);
hcchr.setConnectionRequestTimeout(10000);
return new RestTemplate(hcchr);
}
public String extractSecretValue(String path) {
System.out.println("Test1");
Path secretPath = Paths.get(path);
String value = "";
try (Stream<String> lines = Files.lines(secretPath)) {
value = lines.collect(Collectors.joining());
} catch (IOException ignored) {
throw new ApplicationException(ignored);
}
return value.isEmpty() ? path : value;
}
}
The Test class:
#ExtendWith(MockitoExtension.class)
public class RestTemplateConfigTest {
#Test
public void return_restTemplateConfig() {
RestTemplateConfig restTemplateConfig = new RestTemplateConfig();
RestTemplateConfig restTemplateMock;
RestTemplate restTemplate;
restTemplateMock = Mockito.spy(restTemplateConfig);
try {
when(restTemplateMock.extractSecretValue(anyString())).thenReturn("423424");
restTemplate = restTemplateMock.restTemplate();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new ApplicationException(e);
}
}
}
I've already tried this too:
doReturn("2332").when(restTemplateMock).extractSecretValue(anyString());
If you use when(...).thenReturn(...) the real method will still be invoked
(from Mockito, which is not relevant for your test),
but that should not happen when you use the doReturn(...).when(...) notation instead.
The problem in your test is that token is null and your anyString() does not match that as it only matches non-null strings.
Use any() instead, which matches anything, including nulls.
Combine that with the doReturn(...).when(...) and your test should succeed.
If you do not want the actual methods to be called, then you should be using Mockito.mock() and not Mockito.spy().
you should update your test class to use :
restTemplateMock = Mockito.mock(RestTemplateConfig.class);
You haven't mocked your RestTemplateConfig, you've instantiated it.
What you want is:
restTemplateMock = Mockito.spy(new RestTemplateConfig());