How to set EasyMock expectations after #Autowired injection? - spring

I'm trying to get to grips with EasyMock in order to run some server side integration tests on a spring-ws web service. I have a DAO which I want to mock for my integration testing, I've managed to autowire it successfully, but I can't figure out how to set the expectations post autowire.
I have the following in my spring context xml:
<bean id="accountServiceDao" class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="com.xxx.account.dao.AccountServiceDao" />
</bean>
<bean id="notMockedDao" class="com.xxx.account.dao.AccountServiceDaoImpl"/>
<context:component-scan base-package="com.xxx.account" />
<context:property-placeholder location="classpath:accountDetailService_test.properties" />
<sws:annotation-driven />
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:sql/db_schema.sql" />
<jdbc:script location="classpath:sql/test_data.sql" />
</jdbc:embedded-database>
My dummy test is as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/applicationContext_test.xml" })
public class AccountDetailServiceMockIntergrationTest {
#Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
#Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
/* Set the expectations for the autowired mock dao here */
}
#Test
public void customerEndpoint() throws Exception {
Source requestPayload = new StringSource(TestData.requestXML);
Source responsePayload = new StringSource(TestData.responseXML);
mockClient.sendRequest(withPayload(requestPayload)).andExpect(
payload(responsePayload));
}
}
The endpoint which is hit is below:
#Autowired
private AccountService accountService;
#PayloadRoot(localPart = "AccountSearchRequest", namespace = TARGET_NAMESPACE)
public #ResponsePayload
AccountSearchResponse getAccountDetails(
#RequestPayload AccountSearchRequest request) {
logger.info("Received request | debtornum - " + request.getDebtornum());
AccountSearchResponse accountSearchResponse = objectFactory.createAccountSearchResponse();
AccountDetailsType accountDetails = accountService.getAccountDetails(request.getDebtornum());
accountSearchResponse.setAccountDetails(accountDetails);
logger.info("Returned response | status - " + accountSearchResponse.getAccountDetails().getDebtorStatus().value());
return accountSearchResponse;
}
And here's the service class which contains the DAO which is being mocked
#Service
public class AccountServiceImpl implements AccountService {
//Autowired on a setter
private AccountServiceDao accountServiceDao;
Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class);
#Override
public AccountDetailsType getAccountDetails(BigInteger accountNumber) {
........................
Via debug I can see that the mock DAO is getting injected correctly, but I don't know how to set the behavior on the mock object.
For my unit tests I was able to do the following:
accountDao = EasyMock.createMock(AccountServiceDao.class);
EasyMock.expect(accountDao.checkAccountExists(new BigInteger("12345678"))).andReturn(new Account(new BigInteger("12345678"),"Y",1,0,0,0,"ROI","ROI","DO","10012054082","POST","DD","John Doe","a#a.com","123456"));
EasyMock.replay(accountDao);
testSvc.setAccountServiceDao(accountDao);
I'm not sure how to do the same configuration when the mock is autowired via spring xml config. I'm probably missing something obvious or misunderstanding EasyMock, but any help or guidance would be appreciated.
Thanks

As per Dan's comment above, I've set my expectations as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/applicationContext_test.xml" })
public class AccountDetailServiceMockIntergrationTest {
#Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
#Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
//get the mocked bean from the applicationContext
AccountServiceDao svcDao = (AccountServiceDao)applicationContext.getBean("accountServiceDao");
//reset just in case
EasyMock.reset();
//set expectations on the mock
EasyMock.expect(svcDao.checkAccountExists(new BigInteger("12345678"))).andReturn(new Account(new BigInteger("12345678"),"Y",1,0,0,0,"ROI","ROI","DO","10012054082","POST","DD","John Doe","a#a.com","123456"));
EasyMock.replay(svcDao);
}
#Test
public void customerEndpoint() throws Exception {
Source requestPayload = new StringSource(TestData.requestXML);
Source responsePayload = new StringSource(TestData.responseXML);
mockClient.sendRequest(withPayload(requestPayload)).andExpect(
payload(responsePayload));
}
}
Works fine.

Related

Spring application context bean creation issue with latest spring version

I have a project which uses an old spring.jar (1.2.6),from this project, I am expected to call a newer version (spring version 5.0.7) spring boot project's method. Below is the way I am creating my bean in old version project.
I am getting NullPointer exception while creating the Autowired bean.
Create bean from XML:spring
test-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "qvc-spring-beans.dtd">
<beans>
<bean name="testPci" class="com.test.client.TestPci">
</bean>
</beans>
sampleParent-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans SYSTEM "spring-beans.dtd">
<beans>
<import resource="classpath:/com/test/test-context.xml" />
<bean id="classA" class="com.test.A" >
<property name="testPci">
<ref bean="testPci"/>
</property>
</bean>
</beans>
Java code old spring project:
package com.test;
public class A{
private TestPci testPci;
private ApplicationContext ctx;
public TestPci getTestService() {
if (!StringUtils.isValid(ctx)) {
ctx = new ClassPathXmlApplicationContext("./com/test/test-context.xml");
}
if (!StringUtils.isValid(this.testPci)) {
if (StringUtils.isValid(ctx)) {
testPci = (TestPci) ctx.getBean("testPci");
TestPci testPci = (TestPci) ctx
.getBean("testPci");
this.setSecureTestService(testPci);
}
}
return this.getSecureTestService();
}
public TestPci getSecureTestService() {
return testPci;
}
public void setSecureTestService(TestPci testPci) {
this.testPci = testPci;
}
public void methodA(){
//Calling newer code form old spring code:
testPci.testing("1", "2", "3");
}
}
Calling "TestPci" class as above, but when trying to call using the above, it actually calls the "TestPci"."testing" method. But the object autowired as "testWebClientService" is returning as null. I would like to get the object created instead it returns null.
New spring version class:
#Service
#EnableConfigurationProperties(TestWebClientProperties.class)
#Configurable
public class TestPci{
#Autowired
private TestWebClientService testWebClientService;
public Map<String, String> testing(String a, String b, String c) throws Exception {
Map<String, String> map = testWebClientService.find(a, b, c);
System.out.println("**=="+map.get(0));
return map;
}
}
Adding junit which is used to call the TestPci class from newer version of spring:
#RunWith(SpringJUnit4ClassRunner.class)
#EnableConfigurationProperties(TestWebClientProperties.class)
#SpringBootTest(classes = { TestWebClientService.class, TestPci.class }, webEnvironment = WebEnvironment.NONE)
public class TestJunit {
#MockBean(name="restTemplate")
public RestTemplate restTemplate;
#Autowired
private TestPci testPci;
#Test
public void ff() throws Exception {
testPci.testing("1","1","1");
}
}

Dynamic context - autowiring

I am dynamically adding contexts to the application context with the following code:
#Component
#Scope("singleton")
public class DynamicContextLoader implements ApplicationContextAware {
private static ApplicationContext context;
private Map<String, InterfacePropertyDto> contextMap;
#Autowired
IJpaDao jpaDao;
#PostConstruct
public void init() {
contextMap = (Map<String, InterfacePropertyDto>) context.getBean("contextMap");
contextMap.forEach((contextName, property) -> {
String p = jpaDao.getProperty(property.getPropertyName(), property.getPropertyType());
if (p != null) {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[]{"/META-INF/spring/integration/" + contextName},
false, context);
ctx.refresh();
}
});
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}
This works well and all the beans defined in the new context are created. However the #Autowired does not work for any of these new beans.
For example a bean defined in the new context as:
<bean id="outboundContractJdbcFileMapper" class="com.......integration.model.contract.ContractMapper"/>
has the following autowiring:
public class ContractMapper implements RowMapper<ContractFile> {
#Autowired
IIntegrationDao integrationDao;
#Override
public ContractFile mapRow(ResultSet rs, int rowNum) throws SQLException {
......
}
}
At runtime the outboundContractJdbcFileMapper property integrationDao is null.
Is there a way to force the autowiring to occur when the beans are created? I was hoping that ctx.refresh() would do this.
That doesn't work automatically for the ClassPathXmlApplicationContext. You have to add <context:annotation-config/> to that child context as well:
<xsd:element name="annotation-config">
<xsd:annotation>
<xsd:documentation><![CDATA[
Activates various annotations to be detected in bean classes: Spring's #Required and
#Autowired, as well as JSR 250's #PostConstruct, #PreDestroy and #Resource (if available),
JAX-WS's #WebServiceRef (if available), EJB 3's #EJB (if available), and JPA's
#PersistenceContext and #PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.
Note: This tag does not activate processing of Spring's #Transactional or EJB 3's
#TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext
for information on code-based alternatives to bootstrapping annotation-driven support.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>

Spring: Autowired is null in ejb class

I have the following situation:
#Controller
public class myController {
#Autowired
private IProxy service;
public ModelAndView init(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<String> list = service.getName();
}
}
Then my Service is define as follow:
public interface IProxy {
public List<String> getName();
}
Proxy class is responsible for the lookup to the remote bean
#Service("service")
public class Proxy implements IProxy {
...
public List<String> getName() {
return myClass.getName();
}
And the implementation is the following:
#Interceptors(interceptor.class)
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
#PersistenceContext(unitName = "db")
private EntityManager em;
#Resource
private SessionContext sctx;
#Autowired
public IMyRepo myRepo;
#Override
public List<String> getName() {
try {
return myRepo.getName(em);
}
catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
finally {}
}
So, the problem is that here myRepo is null. I don't know why because IMyRepo and his implementation are always located within the path scanned by Spring.
Just one clarification: MyRepo class that implements IMyRepo is annotated with #Repository.
Any idea?
you can inject spring beans in EJB using Spring interceptors, as explained here in the official documentation. Basically you'll need to adjust your class as follows:
// added the SpringBeanAutowiringInterceptor class
#Interceptors({ interceptor.class, SpringBeanAutowiringInterceptor.class })
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
// your code
}
You'll also need to define the context location in a beanRefContext.xml file (with your own application context file):
application-context.xml version
<bean id="context"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>application-context.xml</value>
</list>
</constructor-arg>
</bean>
Java Configuration version:
<bean id="context"
class="org.springframework.context.annotation.AnnotationConfigApplicationContext">
<constructor-arg>
<list>
<value type="java.lang.Class">com.your.app.Configuration</value>
</list>
</constructor-arg>
</bean>
Spring beans and EJB are two different things, you can't just inject a Spring bean in an EJB, because that EJB is no Spring bean, so Spring doesn't know there is a field which should be injected by Spring (unless you use some fancy AOP stuff, which can enable injection into non-Spring-managed beans).

Spring Abstraction Cache in OSGi Environment

I have problem making Spring Cache working in OSGi Environment. Maybe you can show me what i am missing.
I have configured Spring Cache successfully to work during tests like
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/spring-test.xml"})
public class CacheDictTest {
#Autowired
Dictionary dictionary;
#Test
public void getDict5Times() {
for (int i = 0; i < 5; i++) {
System.out.println(dictionary.getSourceDomains());
}
Assert.assertTrue(true);
}
}
The select is executed once and then i have 5 nice prints.
However I cannot make it work in a bundle
The Cacheable annotation seems to be ignored. Queries are performed everytime i call dictionary.getSourceDomains().
I use ServiceMix 5.3.0 as a container.
My configuration:
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="dictionary"/>
</set>
</property>
</bean>
dictionary:
public class DictionaryImpl implements Dictionary {
private DictionaryDao repository;
public DictionaryDao getRepository() {
return repository;
}
public void setRepository(DictionaryDao repository) {
this.repository = repository;
}
#Override
public List<String> getSourceDomains() {
List<DictEntry> entries = repository.getDictionary(DictTypeEnum.SOURCE_DOMAIN);
List<String> domains = new ArrayList<>();
for(DictEntry entry : entries) {
domains.add(entry.getKey());
}
return domains;
}
}
and dao
public class DictionaryDaoImpl extends BaseDaoImpl implements DictionaryDao {
private static final Logger LOG = LoggerFactory.getLogger(DictionaryDaoImpl.class);
#Override
#Cacheable(value="dictionary", key="#type")
public List<DictEntry> getDictionary(DictTypeEnum type) {
LOG.info("Loading {}", type);
Query q = getSession().createQuery("from DictEntry where type=:type");
q.setParameter("type", new DictType(type.getTypeId()));
List results = q.list();
LOG.debug("Results {}", results);
return results;
}
}
What i tried
Moving #Cacheable annotation to DictionaryDao (interface), to DictionaryImpl or Dictionary (interface) - no effect.
Use different cache implementantion (ehcache instead of JDK ConcurrentMap-based Cache) - no effect
The problem was missing import of Cacheable annotation package in osgi manifest.
org.springframework.cache.annotation
Servicemix did not show any error for missing class, just let the service work ignoring Cacheable annotation.

How to Instantiate spring bean with in a method with runtime constructor arguments?

I need to instantiate a bean ( EmployeeSaver) with in a method with parameter coming in dynamically. I can't use constructor setter for these values are not populated at config time.
Sample code:
class MyEmployeeBean{
public void saveEmployeeDetail (Employee employee , EmployeeHistory hist ){
EmployeeDetail detail = hist.getDetail();
EmployeeSaver eSave = new EmployeeSaver(employee, detail)
saver.saveEmployee();
}
}
class EmployeeSaver {
private Employee empl;
private EmployeeDetail detail;
public EmployeeSaver(Employee emp, EmployeeDetail det){
empl = emp;
detail = det;
}
public void saveEmployee(){
// code to same the guy...
}
}
As MyEmployeeSaver class don't have default constructor so it's throwing runtime exception. I am unsable to use following config as employeeDetail is not know until I do hist.getDetail() !
<bean id="mySaverBean" class="come.saver.EmployeeSaver">
<constructor-arg name="empl" ref="employee" />
<constructor-arg name="hist" ref = "employeeHistory" />
</bean>
How to instantiate employeeSaverBean with constructor arguments?
You can't do this directly with Spring configuration, but using ApplicationContext.getBean(String beanName,Object...args) like described in this question.
MyEmployeeBean must implements ApplicationContextAware to access Spring's context
class MyEmployeeBean implements ApplicationContextAware {
ApplicationContext applicationContext;
void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void saveEmployeeDetail (Employee employee , EmployeeHistory hist ){
EmployeeDetail detail = hist.getDetail();
EmployeeSaver eSave = (EmployeeSaver)this.applicationContextnew.getBean("mySaverBean", employee, detail);
saver.saveEmployee();
}
}
and in beans.xml
<bean id="mySaverBean" class="come.saver.EmployeeSaver" scope="prototype" />
Remeber to addo scope="prototype" to let Spring create a new instance at every request.

Resources