In my spring boot project, one of my Service depends on external service like Amazon. I am writing the integration testing of the Controller classes. So, I want to mock the method in the AmazonService class(as it depends on third party API). The method is void with a single Long argument and can throw a custom application-specific exceptions.
The method is as follows:-
class AmazonService{
public void deleteMultipleObjects(Long enterpriseId) {
String key = formApplicationLogokey(enterpriseId,null);
List<S3ObjectSummary> objects = getAllObjectSummaryByFolder(key);
List<DeleteObjectsRequest.KeyVersion> keys = new ArrayList<>();
objects.stream().forEach(object->keys.add(new DeleteObjectsRequest.KeyVersion(object.getKey())));
try{
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(this.bucket).withKeys(keys);
this.s3client.deleteObjects(deleteObjectsRequest);
log.debug("All the Application logos deleted from AWS for the Enterprise id: {}",enterpriseId);
}
catch(AmazonServiceException e){
throw new AppScoreException(AppScoreErrorCode.OBJECT_NOT_DELETED_FROM_AWS);
}
}}
class Test
class Test
{
#Autowired
AmazonServiceImpl amazonService;
#Autowired
EnterpriseService enterpriseService;
#Before
public void init()
{
amazonService = Mockito.mock(AmazonServiceImpl.class);
Mockito.doNothing().when(amazonService).deleteMultipleObjects(isA(Long.class));
}
#Test
public void testDeleteEnterprise(){
setHeaders();
EnterpriseDTO enterpriseDTO = createEnterpriseEntity(null,"testDeleteEnterpriseName3",null,null,null);
String postUrl = TestUrlUtil.createURLWithPort(TestConstants.ADD_ENTERPRISE,port);
HttpEntity<EnterpriseDTO> request1 = new HttpEntity<>(enterpriseDTO,headers);
ResponseEntity<EnterpriseDTO> response1 = restTemplate.postForEntity(postUrl,request1,EnterpriseDTO.class);
assert response1 != null;
Long enterpriseId = Objects.requireNonNull(response1.getBody()).getId();
String url = TestUrlUtil.createURLWithPort(TestConstants.DELETE_ENTERPRISE,port)+File.separator+enterpriseId;
HttpEntity<EnterpriseDTO> request = new HttpEntity<>(null, headers);
ResponseEntity<Object> response = restTemplate.exchange(url,HttpMethod.DELETE,request,Object.class);
Assert.assertEquals(Constants.ENTERPRISE_DELETION_SUCCESS_MESSAGE,response.getBody());
}
}
class EnterpriseResource
class EnterpriseResource
{
#DeleteMapping("/enterprises/{enterpriseId}")
public ResponseEntity<Object> deleteEnterprise(#PathVariable Long enterpriseId) {
log.debug("REST request to delete Enterprise : {}", enterpriseId);
enterpriseService.delete(enterpriseId);
return ResponseEntity.badRequest().body(Constants.ENTERPRISE_DELETION_SUCCESS_MESSAGE);
}
}
class EnterpriseServiceImpl
class EnterpriseServiceImpl
{
#Override
public void delete(Long enterpriseId) {
log.debug("Request to delete Enterprise : {}", enterpriseId);
enterpriseRepository.deleteById(enterpriseId);
amazonService.deleteMultipleObjects(enterpriseId);
}
}
I have tried various approaches to Mock this method but it didn't work and control is going inside this method during debugging. I want to do nothing in this method during testing.
I have tried the various approaches like throw(), doNothing(), spy() etc.
Please help what is missing here?
Thanks
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 do want to write some functional tests for our project. Techstack: Play Framework 1.5, Java 16, Junit 3.
I found following documentation:
test - 1.5.x
security - 1.5.x
So the Controller looks something like this.
#AllowFeature(Feature.SEARCH_BOX)
public static void search(String term) {
//implementation omitted
TablePage<MyAwesomeType> page = search(term);
render(..., page, term);
}
And my test looks like this
public class SearchTest extends FunctionalTest {
#Test
public void search_withResults() {
String term = "ABC";
Http.Response response = GET("/foo/search?term=" + term);
assertStatus(302, response);
assertThat(renderArgs("page"), is(notNullValue()));
TablePage<MyAwesomeType> page = (TablePage<MyAwesomeType>) renderArgs("page");
assertTrue(page.getTotalRecords() >= 1);
}
}
However, the TablePage<MyAwesomeType> page is null when it really should not be, and i am unable to step into the controller method with the debugger. So it looks like the controller method search(...) is not called at all.
The response Code is 302 - Found but I think this might be play suggestion it found the path /foo/search
My guess is that i need to setup some UserContext or send a authenticityToken along with the request. So play can check the required feature #AllowFeature(Feature.A_SEARCH_BOX).
Does anybody know how I would setup such a functional test?
Any help is appreciated. Thanks!
I was able to figure this out.
I need to log into the application and then the play FunctionalTest.class takes care of the cookie.
Add #NoAuthenticityto the login method
#NoAuthenticity // <-- This enables execution without authenticityToken
public static void login(#Required String username, #Required String password) {
...
}
Post a request to login before the test.
#Test
public void search_withResults() {
// 1. login
Map<String, String> credentials = Map.of("username", "MyUsername", "password", "MyPassword");
POST("/login", credentials);
// Note: session info / authenticityToken is stored in a cookie
// FunctionalTest.class makes sure to use this cookie for subsequent requests
// This request now works like a charm
String term = "ABC";
Http.Response response = GET("/foo/search?term=" + term);
assertStatus(302, response);
assertThat(renderArgs("page"), is(notNullValue()));
TablePage<MyAwesomeType> page = (TablePage<MyAwesomeType>) renderArgs("page");
assertTrue(page.getTotalRecords() >= 1);
}
Note: One can use the JUnit #Before Annotation to simplify the test class.
#Before
public void login(){
Map<String, String> credentials = Map.of("username", "MyUsername", "password", "MyPassword");
POST("/login", credentials);
}
#Test
public void search_withResults() {
String term = "ABC";
Http.Response response = GET("/foo/search?term=" + term);
assertStatus(302, response);
assertThat(renderArgs("page"), is(notNullValue()));
TablePage<MyAwesomeType> page = (TablePage<MyAwesomeType>) renderArgs("page");
assertTrue(page.getTotalRecords() >= 1);
}
#Test
public void anotherTest() { ... }
#Test
public void yetAnotherTest() { ... }
I'm trying for more than an hour to test this class. It went so ugly of stubbing the whole components of the method etc. I'd love some advice how to make a better test or refactor the class to make it way easier to test. I could not figure out a way yet.
Class to Test
#Slf4j
public final class HistoryRestService {
static RestTemplate restTemplate = new RestTemplate();
public static Optional<List<History>> findLatestHistories() {
String url = buildUrl();
ResponseEntity<History[]> responseEntity = null;
try {
responseEntity = restTemplate.getForEntity(url, History[].class);
} catch (ResourceAccessException e) {
log.warn("No connection to History persistence. Please check if the history persistence started up properly");
return Optional.empty();
}
History[] histories = responseEntity.getBody();
return Optional.of(Arrays.asList(histories));
}
private static String buildUrl() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("http://");
stringBuilder.append("localhost");
stringBuilder.append(":8081");
stringBuilder.append("/history/get");
return stringBuilder.toString();
}
// For Testing
static void setRestTemplate(RestTemplate restTemplate) {
HistoryRestService.restTemplate = restTemplate;
}
}
Spock Test which fails
class HistoryRestServiceTest extends Specification {
def "test findLatestHistories"() {
given:
History mockedHistory = Mock()
HistoryRestService uut = new HistoryRestService()
History[] expected = [mockedHistory]
RestTemplate mockedRestTemplate = Stub()
ResponseEntity<History> mockedResponseEntity = Stub()
mockedResponseEntity.getBody() >> expected
mockedRestTemplate.getForEntity(_) >> mockedResponseEntity
uut.setRestTemplate(mockedRestTemplate)
when:
def actual = uut.findLatestHistories()
then:
actual.get() == expected
}
}
I'd suggest using real depedency-injection (spring/guice/cdi) instead of static variables.
Furthermore, you should think about what you want to test, is it the correct request and parsing of the network call, then write an integration test using something like mockserver or wiremock to have the whole stack. Or, if you are just concerned with the result handling, then you could move the code that interacts with RestTemplate into a separate method and use partial mocking to mock this method. I'd suggest to use the real integration test, but for the sake of an example this should work, but I didn't verify the code.
#Slf4j
public class HistoryRestService {
private final RestTemplate restTemplate;
public HistoryRestService() {
restTemplate = new RestTemplate();
}
public HistoryRestService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Optional<List<History>> findLatestHistories() {
try {
return Optional.of(Arrays.asList(getLatestHistories(buildUrl())));
} catch (ResourceAccessException e) {
log.warn("No connection to History persistence. Please check if the history persistence started up properly");
return Optional.empty();
}
}
History[] getLatestHistories(String url) throws {
ResponseEntity<History[]> responseEntity = null;
responseEntity = restTemplate.getForEntity(url, History[].class);
return responseEntity.getBody()
}
private String buildUrl() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("http://");
stringBuilder.append("localhost");
stringBuilder.append(":8081");
stringBuilder.append("/history/get");
return stringBuilder.toString();
}
}
class HistoryRestServiceTest extends Specification {
#Subject
HistoryRestService uut = Spy()
def "test findLatestHistories"() {
given:
History[] expected = [mockedHistory]
when:
def actual = uut.findLatestHistories()
then:
actual.get() == expected
1 * uut.getLatestHistories(_ as String) >> expected
}
def "test findLatestHistories returns empty on exceptions"() {
given:
History[] expected = [mockedHistory]
when:
def actual = uut.findLatestHistories()
then:
!actual.present
1 * uut.getLatestHistories(_ as String) >> {throw new ResourceAccessException()}
}
}
I am writing a JUnit test case for a short method and I think I am setting all the required fields to prevent any NullPointerException but filters is always Null due to which my test doesn't go inside the loop. ILocalPostProcessFilter is an interface that is implemented by BaseExceptionPostProcessFilter which is an abstract class and this abstract class is extended by a concrete class MessageToExceptionPostProcessFilter. I don't have any asserts yet so please ignore it.
Method under test:
protected <T extends BaseServiceResponse> T processLocalPostProcessFilters(T resp, Response cResp) throws EISClientException
{
List<ILocalPostProcessFilter> filters = config.getLocalPostProcessFilters();
if(filters == null)
return resp;
T bResp = resp;
for(ILocalPostProcessFilter filter : filters)
{
bResp = filter.postProcess(resp, cResp);
}
return bResp;
}
JUnit test:
#Test
public void testProcessLocalPostProcessFilters() throws Exception {
TestClass baseClient = new TestClass(new ClientConfiguration(), "serviceURL");
CatastropheServiceResponse catastropheServiceResponse = new CatastropheServiceResponse();
CatastropheResponse entity = new CatastropheResponse();
catastropheServiceResponse.setContentLength(10);
catastropheServiceResponse.setContentType(ContentType.XML);
entity.setSource(ResponseSourceEnum.CATASTROPHE);
entity.setTransactionId("01234");
catastropheServiceResponse.setEntity(entity);
Response response = mock(Response.class);
ILocalPostProcessFilter filter = new MessageToExceptionPostProcessFilter();
((BaseExceptionPostProcessFilter) filter).setHttpStatusCode("200");
((BaseExceptionPostProcessFilter) filter).setCondition(ConditionOperator.OR);
List<ILocalPostProcessFilter> listFilter = new ArrayList<>();
listFilter.add(filter);
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setLocalPostProcessFilters(listFilter);
baseClient.processLocalPostProcessFilters(catastropheServiceResponse, response);
}
Not sure what needs to be done to populate filters.
Any help would be appreciated.
Thanks
I am learning to implement web service using JAX-RS and JAXB, however I couldn't get this to work. The idea is to have a web service that can create a customer(with customer name) and store them in a Hash Map. I tried to create test as well but the test failed with error
javax.ws.rs.ProcessingException: Unable to invoke request
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke
(ApacheHttpClient4Engine.java:287)at
org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke
(ClientInvocation.java:407)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.post
(ClientInvocationBuilder.java:195)
at BloggerTest.addCustomer(StoreTest.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The Failure Trace says `Caused by :javax.ws.rs ProcessingException:
could not find writer for content-type application/xml type: store.domain.Customer
which I don't quite understand.
So below is what I have got at the moment, I'm using the "return singletons" to create instance of the store class:
A Store class:
public class Store {
private Map<String, Customer> _customer;
public Store() {
_customer = new ConcurrentHashMap <String,Customer>();
}
//assume the incoming http request contains customer name
#Post
#Consumes("application/xml")
public Response createCustomer (Customer customer){
_customer.put(customer.getName(), customer);
return Response.created( URI.create("/customers/" + customer.getName()))
.build();
}
}
And a class that runs test:
public class StoreTest {
private static final String WEB_SERVICE_URI = "http://localhost:10000/services/store";
private static Client _client;
#BeforeClass
public static void setUpClient() {
_client = ClientBuilder.newClient();
}
#Before
public void reloadServerData() {
Response response = _client
.target(WEB_SERVICE_URI).request()
.put(null);
response.close();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
#AfterClass
public static void destroyClient() {
_client.close();
}
#Test
public void addCustomer() {
Customer BartSimpsons = new Customer ("BartSimpsons");//create a new customer with name
Response response = _client
.target(WEB_SERVICE_URI).request()
.post(Entity.xml(BartSimpsons));
String location = response.getLocation().toString();
response.close();
Customer BartCreated = _client.target(location).request()
.accept("application/xml").get(Customer.class);
//check if the Customer created by the service has the same name with the original customer
assertEquals(BartSimpsons.getName(), BartCreated.getName());
}
}
I feel that I am missing some important points here, but I really couldn't figure how what I did wrong with the annotations or something else. Can someone please help? Many thanks in advance!
I also faced the same problem. Using #Produces annotation over my service method helped me to resolve the problem. Hope this will help you.