Mocking test class Spring camel - junit

I am new to camel. I am trying to write a test case.
public class A
{
private B b;
public void update(String s){
//calling some methods on B
.....
}
}
Test class
public class TestA extends CamelSpringTestSupport
{
private ClassPathXmlApplicationContext xmlAppContext;
#Test
public void testA()
{
String xml = "some xml";
Endpoint endpoint = context.getEndpoint("direct:incomingxml");
Exchange inExchange = endpoint.createExchange();
inExchange.getIn().setBody(xml);
inExchange.setPattern(ExchangePattern.InOnly);
template.send(endpoint, inExchange);
}
#Override
protected AbstractApplicationContext createApplicationContext()
{
xmlAppContext = new ClassPathXmlApplicationContext(
"classpath:/test-camel-context.xml");
return xmlAppContext;
}
}
spring bean xml
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:incomingxml"/>
<to uri="bean:classA?method=update"/>
</route>
</camelContext>
<bean id="b" class="B">
</bean>
<bean id="classA" class="A">
<constructor-arg index="0" ref="b" />
</bean>
There are couple of test cases pre-written using real objects. Is there any way I can mock this class B, gets injected in class A and mock few methods? I want to do in my test case only so that pre-written test cases remain unaffected?

You can solve this by adding a setter in you class A.
The application context will be loaded and A's B object will be injected by the bean declared in the XML but you can still override it with a mock of B by calling the newly defined setter in your test.
Then by doing that, B's mock will be used in your test and no the bean. The other test cases will not be affected.

Related

How to Mock Service class while writing a Junit for Spring-ws endpoint

I have created a Spring SOAP based webservice which retrives data from my DB , I am able to test the service through SOAP UI , but now I am trying to add few functionalites for the service and I want to add some Junits for the service , Please find my Endpoint and Junit details below.
My End Point Class
#Endpoint
public class CountryEndPoint {
private static final String NAMESPACE_URI = "http://tutorialspoint/schemas";
#Autowired
CountryRepository countryRepository;
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
#ResponsePayload
public GetCountryResponse getCountry(#RequestPayload GetCountryRequest request) throws JDOMException {
Country country = countryRepository.findCountry(request.getName());
GetCountryResponse response = new GetCountryResponse();
response.setCountry(country);
return response;
}
}
Spring-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan
base-package="com.tutorialspoint" />
<sws:annotation-driven />
<bean id="schema"
class="org.springframework.core.io.ClassPathResource">
<constructor-arg index="0" value="*.xsd" />
</bean>
</beans>
Junit-Test calss
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/spring-context.xml")
public class CustomerEndPointTest {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private ResourceLoader resourceLoader;
private MockWebServiceClient mockClient;
private Resource schema = new ClassPathResource("countries.xsd");
#Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
GenericApplicationContext ctx = (GenericApplicationContext) applicationContext;
final XmlBeanDefinitionReader definitionReader = new XmlBeanDefinitionReader(ctx);
definitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
definitionReader.setNamespaceAware(true);
}
#Test
public void testCountryEndpoint() throws Exception {
Resource request = resourceLoader.getResource("request.xml");
Resource response = resourceLoader.getResource("response.xml");
mockClient.sendRequest(withPayload(request)).
andExpect(payload(response)).
andExpect(validPayload(schema));
}
}
I am able to run the test case with out any issue but my problem is I am not able to mock my service class (CountryRepository) mock the the code below.
Country country = countryRepository.findCountry(request.getName());
Does any one have any suggessions on this?
From your test case, I suppose your are trying to mock the CrudRepository object from inside a webservice call: That would be called integration testing. You need to make a choice for unit testing:
Test the request, and assert its response http status code (for example),
Or test the getCountry method inside your CountryEndPoint class. Doing both options at the same time would be considered an integration test.
I will try to answer considering the unit test case, using option 2. I think it will give you better insights for the future.
You are injecting the dependency of the CountryRepository on your CountryEndPoint class. You need to do the same on your testing class. For example, a basic setup would be:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/spring-context.xml")
public class CustomerEndPointTest {
#InjectMocks
private CountryEndPoint countryEndPoint;
#Mock
private CountryRepository countryRepository;
#Test
public void testCountryEndpoint() throws Exception {
Mockito.when(countryRepository //...
countryEndPoint.getCountry(request //build a request object and pass it here.
//assertions...
}
}
Then, whenever a method from CountryRepository is invoked, it will be invoked from the mock instead. This is only possibly because of the injection of the mock via annotations.
If you actually send a request, using a HTTP client (like you intended), you cannot mock the methods being invoked inside your controller class, because you are not manipulating and assigning the instances yourself, and thus are not able to determine what is a mock, and what is not.

SpringBatch ItemProcessor: process a List<?> not one Item

I have to modify a process made with SpringBatch, the procedure it's easy.
Actually, the program reads records from a database and exports the results to XML files (one by each table)
Now, I want to write JSON files instead XML files, I didn't find how to make it possible, but reading and reading I have something close to that I want.
I wrote an ItemProcessor class like this
#Component("jSONObjectProcessor")
public class JSONObjectProcessor implements ItemProcessor<Object, String> {
private Gson gson = new Gson();
private List<Object> array = new ArrayList<Object>();
#Override
public String process(Object item) throws Exception {
array.add(item);
return gson.toJson(array);
}
}
Obviously, if I have 6 items; this going to return 6 List, like it does right now
1st item
[
{
"number":0,
"string":"abc",
"desc":"abcdefg"
}
]
2nd item
[
{
"number":0,
"string":"abc",
"desc":"abcdefg"
},
{
"number":1000,
"string":"xyz",
"desc":"uvwxyz"
}
]
//more lists by the total of items
To write the files I'm using org.springframework.batch.item.file.FlatFileItemWriter class.
I want to find the way to return all the items in a List and give it JSON form and write this json in the file. I'm in the correct way or there are another, more elegant form. It's possible?
Thanks!
Update
I have made the changes (thanks #Sanj), but I miss the comma (,) delimiter between each object.
My ItemWriter it's defined like this
<bean id="itemWriterRegConstantes" scope="step"
class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="#{jobParameters['fileOutput']}" />
<property name="shouldDeleteIfExists" value="true" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="," />
</bean>
</property>
<property name="footerCallback" ref="headerFooterCallback" />
<property name="headerCallback" ref="headerFooterCallback" />
</bean>
The output file now looks like this
[
{"number":0,"string":"abcd","desc":"efgh"} //no comma
{"number":1000,"string":"xyz","valor":"xyzw"}
]
How add it?
Additionaly, how can I print all the content in a single line? (to minify the content) It's possible?
My Solution
I had to create my own class (really I made change to the FlatFileItemWriter SpringBatch class, it's here
Output: a file with an one line JSON array content.
Thanks!
Return single json for every item from ItemProcessor
#Component("jSONObjectProcessor")
public class JSONObjectProcessor implements ItemProcessor<Object, String> {
private Gson gson = new Gson();
#Override
public String process(Object item) throws Exception {
return gson.toJson(item);
}
}
Create header and footer call backs. Basically they will be used to start and close the array respectively.
public class JSONHeaderFooterCallBack implements FlatFileHeaderCallback, FlatFileFooterCallback{
#Override
public void writeHeader(Writer writer) throws IOException {
writer.write("[" + System.getProperty("line.separator"));
}
#Override
public void writeFooter(Writer writer) throws IOException {
writer.write("]");
}
}
Associate the callbacks with FlatFileItemWriter
FlatFileItemWriter<String> writer = new FlatFileItemWriter<String>();
//Setting header and footer.
JSONHeaderFooterCallBack headerFooterCallback = new JSONHeaderFooterCallBack();
writer.setHeaderCallback(headerFooterCallback);
writer.setFooterCallback(headerFooterCallback);
writer.setResource(new FileSystemResource(System.getProperty("user.dir") + "/output.json"));
Now you can use "writer" to write all records as a json array to a file.
---update--
Use CustomLineAggregator to append comma at the end of every record:
public class CustomLineAggregator<String> implements LineAggregator<String> {
#Override
public String aggregate(String item) {
return item+",";
}
}

Wrap a primitive returned from a Spring controller into json

For now, I am using something like this:
#RequestBody
#RequestMapping("whatever")
public ObjectWrapper<Integer> foo() {
return new ObjectWrapper<>(42);
}
What I would like to do is to rewrite the method in the following way
#RequestBody
#RequestMapping("whatever")
public int foo() {
return 42;
}
and get 42 (or any other primitive) wrapped into ObjectWrapper before it gets serialized (by Jackson) and gets written into response. I wonder if it is actually possible and, if so, how to do that.
As I have misunderstood your question, I updated my answer:
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
super.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
}
}
Add to default message converter:
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
<bean id="jacksonObjectMapper" class="com.mysite.CustomObjectMapper" />
However this might not produce the output you desired.
Best thing is to write your own serializer and use it with your custom object mapper and wrap primitives in your serializer.
Here is something related: https://github.com/FasterXML/jackson-databind/issues/34

Spring Data Rest - Configure pagination

Using Spring Data REST with JPA in version 2.1.0.
How can I configure the pagination in order to have the page argument starting at index 1 instead of 0 ?
I have tried setting a custom HateoasPageableHandlerMethodArgumentResolver with an mvc:argument-resolvers, but that doesn't work:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver">
<property name="oneIndexedParameters" value="true"/>
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
Note that this behaviour is perfectly coherent with the documentation for mvc:argument-resolver that says:
Using this option does not override the built-in support for
resolving handler method arguments. To customize the built-in support
for argument resolution configure RequestMappingHandlerAdapter
directly.
But how can I achieve this ? If possible, in a clean and elegant way ?
The easiest way to do so is to subclass RepositoryRestMvcConfiguration and include your class into your configuration:
class CustomRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Override
#Bean
public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
HateoasPageableHandlerMethodArgumentResolver resolver = super.pageableResolver();
resolver.setOneIndexedParameters(true);
return resolver;
}
}
In your XML configuration, replace:
<bean class="….RepositoryRestMvcConfiguration" />
with
<bean class="….CustomRestMvcConfiguration" />
or import the custom class instead of the standard one in your JavaConfig file.
I have configured the RequestMappingHandlerAdapter using a BeanPostProcessor, however I believe that's neither clean, nor elegant. That looks more like a hack. There must be a better way ! I'm giving the code below just for reference.
public class RequestMappingHandlerAdapterCustomizer implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter)bean;
List<HandlerMethodArgumentResolver> customArgumentResolvers = adapter.getCustomArgumentResolvers();
if(customArgumentResolvers != null) {
for(HandlerMethodArgumentResolver customArgumentResolver : customArgumentResolvers) {
if(customArgumentResolver instanceof HateoasPageableHandlerMethodArgumentResolver) {
HateoasPageableHandlerMethodArgumentResolver hateoasPageableHandlerMethodArgumentResolver = (HateoasPageableHandlerMethodArgumentResolver)customArgumentResolver;
hateoasPageableHandlerMethodArgumentResolver.setOneIndexedParameters(true);
}
}
}
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}
<beans ...>
<bean class="util.spring.beanpostprocessors.RequestMappingHandlerAdapterCustomizer" />
</beans>
I use to do it using a customizer, which is something that they keep adding for more and more components with every new version:
#Bean
public PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() {
return resolver -> resolver.setOneIndexedParameters(true);
}
You can put this in any #Configuration class, but ideally you should put it (with any other customization) in one that implements RepositoryRestConfigurer.

Spring #ResponseBody Jackson JsonSerializer with JodaTime

I have below Serializer for JodaTime handling:
public class JodaDateTimeJsonSerializer extends JsonSerializer<DateTime> {
private static final String dateFormat = ("MM/dd/yyyy");
#Override
public void serialize(DateTime date, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String formattedDate = DateTimeFormat.forPattern(dateFormat).print(date);
gen.writeString(formattedDate);
}
}
Then, on each model objects, I do this:
#JsonSerialize(using=JodaDateTimeJsonSerializer.class )
public DateTime getEffectiveDate() {
return effectiveDate;
}
With above settings, #ResponseBody and Jackson Mapper sure works. However, I don't like the idea where I keep writing #JsonSerialize. What I need is a solution without the #JsonSerialize on model objects. Is it possible to write this configuration somewhere in spring xml as a one configuration?
Appreciate your help.
Although you can put an annotation for each date field, is better to do a global configuration for your object mapper. If you use jackson you can configure your spring as follow:
<bean id="jacksonObjectMapper" class="com.company.CustomObjectMapper" />
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" >
</bean>
For CustomObjectMapper:
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
configure(Feature.WRITE_DATES_AS_TIMESTAMPS, false);
setDateFormat(new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)"));
}
}
Of course, SimpleDateFormat can use any format you need.
#Moesio pretty much got it. Here's my config:
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven/>
<!-- Instantiation of the Default serializer in order to configure it -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterConfigurer" init-method="init">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper" class="My Custom ObjectMapper"/>
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
The bit that got me is that <mvc:annotation-driven/> makes its own AnnotationMethodHandler and ignores the one you make manually. I got the BeanPostProcessing idea from http://scottfrederick.blogspot.com/2011/03/customizing-spring-3-mvcannotation.html to configure the one that gets used, and voilà! Works like a charm.
Same using JavaConfig of Spring 3:
#Configuration
#ComponentScan()
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter
{
#Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters)
{
converters.add(0, jsonConverter());
}
#Bean
public MappingJacksonHttpMessageConverter jsonConverter()
{
final MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter();
converter.setObjectMapper(new CustomObjectMapper());
return converter;
}
}
If you are using Spring Boot, try this in application.yml :
spring:
jackson:
date-format: yyyy-MM-dd
time-zone: Asia/Shanghai
joda-date-time-format: yyyy-MM-dd
If you simply have the Jackson JARs on your classpath, and return a #ResponseBody, Spring will automatically convert the Model object to JSON. You don't need to annotate anything in the Model to get this to work.