I want to write junit for below method
public class ManageProfile{
public ResponseDTO create(SessionContext context, String flowId, Map<String, String> params) {
ApiClient apiClient=new ApiClient();
apiClient.setBasePath("ip");
Service service=new Service();
service.setApiClient(apiClient);
ResponseDTO response= service.createProfile(new RequestDto());
return response;
}
}
Its not spring based application.
class Test
#Test
public void testCreate() {
SessionContext sessionContext = mock(SessionContext.class);
ManageProfile manageProfile=new ManageProfile();
Service service=mock(Service.class);
when(service.createProfile(any())).thenReturn(new ResponseDTO());
String flowId = "1";
Map<String, String> params = new HashMap<>();
ResponseDTO responseDTO=manageProfile.create(sessionContext,flowId,params);
Assert.assertEquals("123"responseDTO.getId);
}
}
I am not able to inject mock Service object in ManageProfile as it is getting created using new keyword
Use spy to mock some methods in ManageProfile class
public class ManageProfile{
public ResponseDTO create(SessionContext context, String flowId, Map<String, String> params) {
ApiClient apiClient=new ApiClient();
apiClient.setBasePath("ip");
Service service = createService();
...
}
public Service createService(){
return new Service();
}
class Test {
#Test
public void testCreate() {
SessionContext sessionContext = mock(SessionContext.class);
ManageProfile manageProfile= spy(new ManageProfile());
Service service=mock(Service.class);
when(mangaeProfile.createService()).thenReturn(service);
...
}
Related
I am facing issues in mocking static method.
Below is my code where I am calling a static method
public class GetAllBatches {
public HttpResponseMessage run(
#HttpTrigger(route = "v1/batches",
name = "request",
methods = {HttpMethod.GET},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<String> request,
final ExecutionContext context){
context.getLogger().info("List batches Called");
String apiResponse ;
String connector = request.getQueryParameters().getOrDefault("connector", "");
try{
BatchesController batchesController = BatchesController.getInstance();
apiResponse = new Gson().toJson(batchesController.getBatches(connector));
}
}
}
BatchesController Class :
public class BatchesController {
Logger log = Logger.getLogger(BatchesController.class.getName());
public static BatchesController getInstance() {
if (batchesController == null) {
batchesController = new BatchesController(BatchDaoFactory.getDao());
}
return batchesController;
}
private static BatchesController batchesController = new BatchesController();
private final BatchDao batchDao;
public BatchesController(BatchDao BatchDao) {
this.batchDao = BatchDao;
}
// Do something
}
And below is the test that I have :
#RunWith(MockitoJUnitRunner.class)
public class GetAllBatchesTest {
#Mock
ExecutionContext context;
#Mock
HttpRequestMessage<String> request;
#Mock
BatchesController batchesController;
#Mock
BatchDao BatchDao;
#InjectMocks
GetAllBatches getAllBatchesMock = new GetAllBatches();
#Before
public void setUp() {
Map<String, String> map = new HashMap<>();
map.put("connector", "");
doReturn(Logger.getGlobal()).when(context).getLogger();
doReturn(map).when(request).getQueryParameters();
try (MockedStatic<BatchesController> utilities = Mockito.mockStatic(BatchesController.class)) {
utilities.when(BatchesController::getInstance).thenReturn(batchesController);
}
doAnswer((Answer<HttpResponseMessage.Builder>) invocationOnMock -> {
HttpStatus status = (HttpStatus) invocationOnMock.getArguments()[0];
return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status);
}).when(request).createResponseBuilder(any(HttpStatus.class));
}
#Test
public void testHttpTriggerJava() {
final HttpResponseMessage ret = getAllBatchesMock.run(request, context);
Assertions.assertEquals(ret.getStatus(), HttpStatus.OK);
}
When I run my test, it throws an error message :
java.lang.ExceptionInInitializerError
BatchesController.getInstance() is not actually returning the mock value.
I am not sure what is going wrong here ?
UPDATE :
I found out that the problem is because I am using Mockito-inline Mockito-inline fails to initiate mock on class but initiates mock only on interfaces
You are using a try-with-resources block to setup a static mock:
try (MockedStatic<BatchesController> utilities = Mockito.mockStatic(BatchesController.class)) {
utilities.when(BatchesController::getInstance).thenReturn(batchesController);
}
Remember that the static mock is only active in scope of the block - after you exit the block the resource is closed.
Thus, you need to:
move the static mock initialization from setup method to the test method
run code under test within the try-with-resources block
I am new to Spring Integration so please forgive and correct me if my question is absurd. I am trying to write Unit test cases for Spring Integration application where I am testing only controller and looking to mock service call.
Test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({HeaderUtils.class})
#PowerMockIgnore({ "javax.management.*", "javax.script.*" })
public class DocMgmtImplTestPower {
private MockMvc mvc;
#InjectMocks
private DocMgmtImpl docMgmtImpl;
#Mock
DocMgmtService docMgmtServiceGateway;
#Mock
SendComnMsgResponse sendComnMsgResponse;
#Before
public void init() {
MockitoAnnotations.initMocks(this); //
mvc = MockMvcBuilders.standaloneSetup(DocMgmtImpl.class).build();
PowerMockito.mockStatic(HeaderUtils.class, new Answer<Map<String, Object>>() {
#Override
public Map<String, Object> answer(InvocationOnMock arg0) throws Throwable {
Map<String, Object> headers = new HashMap<String, Object>();
HeaderInfo headerInfo = new HeaderInfo();
headers.put(BusinessServiceConstants.SERVICE_HEADER, headerInfo);
return headers;
}
});
}
#SuppressWarnings("deprecation")
#Test
public void testMethod() throws Exception {
SpecialFormMsgRequest arg = new SpecialFormMsgRequest();
Map<String, Object> headers = new HashMap<String, Object>();
Mockito.when(docMgmtServiceGateway.specialFormMsg(Mockito.any(SpecialFormMsgRequest.class),
(Matchers.<Map<String, Object>>any()))).thenReturn(new SendComnMsgResponse());
SpecialFormMsgRequest msg = new SpecialFormMsgRequest();
msg.setUiStaticDocFlag("N");
mvc.perform(post("/specialMsg").accept(MediaType.APPLICATION_JSON).content(asJsonString(msg))
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk());
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Controller:
#Controller
public class DocMgmtImpl implements DocMgmt {
#Autowired
**DocMgmtService docMgmtServiceGateway;** **// I want to mock this service.**
#Override
#RequestMapping(value = "/specialMsg", method = RequestMethod.POST)
#ResponseBody
public SendComnMsgResponse specialMsg(#Valid #RequestBody final SpecialFormMsgRequest specialFormMsgRequest)
throws BusinessException, TechnicalException {
SendComnMsgResponse sendComnMsgResponse = null;
try {
Map<String, Object> headers = HeaderUtils.getHeaders(poBusinessHeader); // PowerMockito working here...
sendComnMsgResponse = **this.docMgmtServiceGateway.specialFormMsg(specialFormMsgRequest, headers);** // docMgmtServiceGateway is getting null...
} catch (Exception exception) {
handleException(exception);
}
return sendComnMsgResponse;
}
}
Gateway.xml:
<int:gateway id="docMgmtServiceGateway" service-interface="group.doc.svc.gateway.DocMgmtService"
default-reply-channel="docReplyChannel" error-channel="docErrorChannel">
<int:method name="sendComnMsg" request-channel="sendComnMsgRequestChannel" />
</int:gateway>
si-chain.xml:
<int:chain input-channel="esDBBISendComnMsgRequestChannel" output-channel="docReplyChannel">
<int:transformer method="formatRequest" ref="esSendComnMsgTransformer"/>
<int:service-activator ref="sendComnMsgActivator" method="sendComnMsg" />
<int:transformer method="parseResponse" ref="esSendComnMsgTransformer"/>
</int:chain>
I am wondering, whether I am doing correct or not. Because DocMgmtService service is an interface and it don't have implementation. After controller call goes to Transformer as configured above. On this setup I have following quetions.
Can I mock DocMgmtService service with same setup if not what will be correct approach.
If yes then how can I mock my service.
Thanks
It depends on exactly what you want to test.
If you mock the interface, all you are testing is your mock stubbing for that interface (pointless).
The framework creates an implementation of the interface which creates a message from the parameters and sends it to the channel.
You should auto wire the gateway into your test and call it.
You can mock any of the downstream components (e.g. sendComnMsgActivator) as needed.
I have a class below for which I want to write a unit test
abstract class ProductImpl{
#Inject DataServices ds; // using Guice
public Response parse(String key, Long value){
Response res = ds.getResponseObject(); // Response object is created using DataServices object
res.id = key;
res.code = value;
}
}
And I have a test as below
class ProductImplTest{
#InjectMocks ProductImpl impl;
Map<String, Long> map;
#Before
map.put("abc", 10L);
map.put("xyz", 11L);
}
#Test
public void test(){
for(String key: map.keySet()){
Response res = impl.parse(key, map.get(key));
// and check if fields of Response object are set correctly i.e res.id is abc and value is 10L
}
}
But when i debug the test and control goes to parse method , DataServices object ds is null. How to instantiate this object through test . I do not want to use mocking, I want real response objects to be created and test the values set in them.
You can use Mockito
#RunWith(MockitoJUnitRunner.class)
class ProductImplTest {
#Mock DataService dService;
#InjectMocks ProductImpl sut;
#Test
public void test() {
ResponseObject ro = new ResponseObject();
String string = "string";
Long longVal = Long.valueOf(123);
sut.parse("string", longVal);
verify(dService).getResponseObject();
assertThat(ro.getId()).isEqualTo("string");
// you should use setters (ie setId()), then you can mock the ResponseObject and use
// verify(ro).setId("string");
}
}
EDIT:
With ResponseObject being an abstract class or preferably an interface, you'd have
interface ResponseObject {
void setId(String id);
String getId();
// same for code
}
and in your test
#Test public void test() {
ResponseObject ro = mock(ResponseObject.class);
// ... same as above, but
verify(dService).getResponseObject();
verify(ro).setId("string"); // no need to test getId for a mock
}
Try with constructor injection:
class ProductImpl{
DataServices ds;
#Inject
public ProductImpl(DataServices ds) {
this.ds = ds;
}
}
Let me thank you in advance for your help!
I have a weird behaviour in an spring boot application. Let me explain it for you:
I'm wrapping some legacy web services (custom xml messages) with some nice rest-json services (via spring-mvc and spring boot and using jackson for serializing stuff)
In order to communicate with the legacy systems, I have created a custom XmlMapper, serializers and deserializers.
And finally, I have created an httpclientconfig, in order to define some http connection properties...
But after starting the app and trying to visit any endpoint (actuator ones for example), the app only returns xml. Event swagger endpoints return xml (what makes swagger-ui going nuts.
These are some of the classes:
#Configuration
public class HttpClientConfig {
private static final Logger logger = LoggerFactory.getLogger(HttpClientConfig.class);
#Value(value = "${app.http.client.max_total_connections}")
public String MAX_TOTAL_CONNECTIONS;
#Value(value = "${app.http.client.max_connections_per_route}")
public String MAX_CONNECTIONS_PER_ROUTE;
#Value(value = "${app.http.client.connection_timeout_milliseconds}")
public String CONNECTION_TIMEOUT_MILLISECONDS;
#Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
#Autowired
private XmlMapper xmlMapper;
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
}
if (converter instanceof MappingJackson2XmlHttpMessageConverter) {
MappingJackson2XmlHttpMessageConverter jsonConverter = (MappingJackson2XmlHttpMessageConverter) converter;
jsonConverter.setObjectMapper(xmlMapper);
}
}
logger.debug("restTemplate object created====================================");
return restTemplate;
}
#Bean
public HttpClient httpClient() {
HttpClient httpClient = null;
try {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// disable SSL check
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
return true;
}
}).build();
httpClientBuilder.setSSLContext(sslContext);
// don't check Hostnames
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory).build();
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connMgr.setMaxTotal(Integer.parseInt(MAX_TOTAL_CONNECTIONS));
connMgr.setDefaultMaxPerRoute(Integer.parseInt(MAX_CONNECTIONS_PER_ROUTE));
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(Integer.parseInt(CONNECTION_TIMEOUT_MILLISECONDS)).build();
httpClientBuilder.setDefaultRequestConfig(config);
httpClientBuilder.setConnectionManager(connMgr);
// to avoid nohttpresponse
httpClientBuilder.setRetryHandler(new HttpRequestRetryHandler() {
#Override
public boolean retryRequest(IOException exception, int executionCount,
org.apache.http.protocol.HttpContext context) {
// TODO Auto-generated method stub
return true;
}
});
httpClient = httpClientBuilder.build();
} catch (Exception e) {
logger.error("Excption creating HttpClient: ", e);
}
return httpClient;
}
}
And the xml mapper
#Configuration
public class XmlMapperConfig{
#Bean
public XmlMapper getXmlMapper() {
XmlMapper mapper=new XmlMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(CafRequestObject.class, new CafRequestObjectSerializer());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(module);
mapper.findAndRegisterModules();
CafXmlSerializationProvider cafXmlProvider=new CafXmlSerializationProvider(new XmlRootNameLookup());
mapper.setSerializerProvider(cafXmlProvider);
return mapper;
}
}
I call to findAndregisterModules, because I am also developing some libraries which provides additional serializers for services (modularized stuff)
I'm completely lost with this. Any help would be much appreciated...
Regards!
I have solved it extending WebMvcConfigurerAdapter:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Thanks again!
public class RESTDataServiceClient{
private Client client;
private String dataServiceUri;
private String dataServiceResource;
private CustomData customData;
public RESTDataServiceClient(String dataServiceUri, String dataServiceResource, Client client){
this.client = client;
this.dataServiceUri = dataServiceUri;
this.dataServiceResource = dataServiceResource;
}
#Override
public CustomData getCustomData() {
WebTarget dataServiceTarget = client.target(dataServiceUri).path(dataServiceResource);
Invocation.Builder invocationBuilder = dataServiceTarget.request(MediaType.APPLICATION_JSON_TYPE);
Response response = invocationBuilder.get();
myCustomData = response.readEntity(CustomData.class);
return myCustomData;
}
}
CustomData.java
public class CustomData{
private TLongObjectMap<Map<String, TIntIntMap>> data;
public CustomData() {
this.data = new TLongObjectHashMap<>();
}
//getter and setter
}
sample json content
{"50000":{"testString":{"1":10}},"50001":{"testString1":{"2":11}} }
I am trying to get data from a data service which is going to return data in a JSON format. I am trying to write a client to read that JSON into a custom object. The CustomData contains a nested trove map datastructure. we wrote a custom serializer for that and the server part works fine. I am unable to get the rest client read the data into an object, but reading into string works. I tried above pasted code with the sample data and i get the error below.
javax.ws.rs.ProcessingException: Error reading entity from input stream.
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:866)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:783)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:326)
at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:111)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:399)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:108)
at com.sample.data.RESTDataServiceClient.getCustomData(RESTDataServiceClient.java:42)
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "50000" (class com.sample.data.CustomData), not marked as ignorable (0 known properties: ])
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#2cb89281; line: 1, column: 14] (through reference chain: com.sample.data.CustomData["50000"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:671)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:773)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1297)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1275)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:247)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1233)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:677)
at com.fasterxml.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:777)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:264)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:234)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:154)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1124)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:851)
... 38 more
TLongObjectMap is not deserializable out of the box, so how you made a custom serializer you also need to implement a custom deserializer. You can package these up nicely in a module and add it to your ObjectMapper.
It looks like there is a Trove module in development right now, which you can download and add to your ObjectMapper the same as the example below. The TIntObjectMapDeserializer implementation in that link is much more robust then my solution, so I would recommend using that class in your project if possible.
If you want to try and write it yourself, here's a starting point that properly deserializes your provided example:
public class FakeTest {
#Test
public void test() throws Exception {
ObjectMapper om = new ObjectMapper();
om.registerModule(new CustomModule());
String s = "{\"50000\":{\"testString\":{\"1\":10}},\"50001\":{\"testString1\":{\"2\":11}} }";
CustomData cd = om.readValue(s, CustomData.class);
System.out.println(cd.getData());
}
public static class CustomData {
private TLongObjectMap<Map<String, TIntIntMap>> data;
public CustomData() {
this.data = new TLongObjectHashMap<>();
}
public TLongObjectMap<Map<String, TIntIntMap>> getData() { return data; }
public void setData(TLongObjectMap<Map<String, TIntIntMap>> data) { this.data = data; }
}
public static class CustomModule extends SimpleModule {
public CustomModule() {
addSerializer(CustomData.class, new CustomSerializer());
addDeserializer(CustomData.class, new CustomDeserializer());
}
public static class CustomSerializer extends JsonSerializer<CustomData> {
#Override
public void serialize(CustomData value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
// add custom serializer here
}
}
public static class CustomDeserializer extends JsonDeserializer<CustomData> {
#Override
public CustomData deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
TLongObjectMap<Map<String, TIntIntMap>> data = new TLongObjectHashMap<>();
ObjectNode node = jsonParser.getCodec().readTree(jsonParser);
Iterator<Map.Entry<String,JsonNode>> fields = node.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
ObjectNode value = (ObjectNode) entry.getValue();
Map.Entry<String, JsonNode> innerField = value.fields().next();
ObjectNode innerNode = (ObjectNode) innerField.getValue();
Map.Entry<String, JsonNode> innerInnerField = innerNode.fields().next();
TIntIntMap intMap = new TIntIntHashMap();
intMap.put(Integer.parseInt(innerInnerField.getKey()), innerInnerField.getValue().asInt());
Map<String, TIntIntMap> innerMap = Collections.singletonMap(innerField.getKey(), intMap);
data.put(Long.parseLong(entry.getKey()), innerMap);
}
CustomData customData = new CustomData();
customData.setData(data);
return customData;
}
}
}
}