Spring boot: Unit test and Config file - java

I am doing unit tests for a rest controller, which is only a small part of a bigger application.
My test context isn't recognized by my application and I have the following exception : java.lang.IllegalStateException: Failed to load ApplicationContext
This is my test class:
Test RestController
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(locations = "classpath:/META-INF/spring/context-test.xml")
#WebIntegrationTest
public class MyRestControllerTest extends AbstractTransactionnalTest {
#Autowired
private IManager manager;
#Test
// my unit tests
}
The thing is that if instead of locations = "classpath:/META-INF/spring/context-test.xml" I use classes = Production.class with the following application class, it works fine:
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableScheduling
#ImportResource({ "classpath:/META-INF/spring/context-production.xml" })
public class Production {
// class content
}
I've read all the posts with similar problem and I know it is linked to the #Configuration and #EnableAutoConfiguration annotation however when I tried a custom configuration class which used these annotation and imported the settings from the context.xml it did not work.
I ideally wish not to add any configuration class and would like to only add a bean to my test-context.xml.
Is it possible to solve this issue with a bean in my context.xml or an annotation on TestRestController ?
Here is my stack trace:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
... 26 more
Caused by: org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
... 35 more
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:185)
... 39 more
Here is the bean I used to mock the manager in my test-context.xml :
<bean id="IManager"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.service.impl.Manager"/>
Update :
I tried to used a custom manager mock where the database is replaced with a list.
If I remove the annotation #WebIntegrationTest, the application context loads correctly however I get another exception because the server isn't launched without the #WebIntegrationTest annotation.
I/O error on GET request for network address :Connection refused
I am running on spring 1.3.7.

#ContextConfiguration defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests. Specifically #ContextConfiguration declares the application context resource locations or the annotated classes that will be used to load the context.
#ContextConfiguration("/test-config.xml")
public class XmlApplicationContextTests {
// class body...
}
Spring Boot provides a
#SpringBootTest 
annotation which can be used as an alternative to the standard spring-test
#ContextConfiguration 
annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests via SpringApplication.
You can use the webEnvironment attribute of #SpringBootTest to further refine how your tests will run.
Spring Boot’s #*Test annotations will search for your primary configuration automatically whenever you don’t explicitly define one.
The search algorithm works up from the package that contains the test until it finds a #SpringBootApplication or #SpringBootConfiguration annotated class. As long as you’ve structured your code in a sensible way your main configuration is usually found.
If you want to customize the primary configuration, you can use a nested #TestConfiguration class. Unlike a nested #Configuration class which would be used instead of a your application’s primary configuration, a nested #TestConfiguration class will be used in addition to your application’s primary configuration.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html 40.2

Related

Spring is unable to inject an EntityManager using #PersistenceContext

I have a Java 8/spring 4.3.5.RELEASE web application tha runs on a wildfly 10 server. I use a persistence.xml file. I enabled trace logging on the jboss jpa and hibernate classes and I can see this file gets picked up and is resolved smoothly into a persistence unit:
DEBUG [] [org.hibernate.jpa.internal.util.LogHelper] PersistenceUnitInfo [
name: testcontext
persistence provider classname: org.hibernate.jpa.HibernatePersistenceProvider
classloader: ModuleClassLoader for Module "deployment.BasicWebapp.war:main" from Service Module Loader
excludeUnlistedClasses: false
JTA datasource: org.jboss.as.connector.subsystems.datasources.WildFlyDataSource#fb80232
Non JTA datasource: null
Transaction type: JTA
PU root URL: vfs:/C:/Users/Me/Wildfly 10.0.0/standalone/deployments/BasicWebapp.war/WEB-INF/classes/
Shared Cache Mode: UNSPECIFIED
Validation Mode: AUTO
Jar files URLs []
Managed classes names [
com.company.project.data.User]
Mapping files names []
Properties [
jboss.entity.manager.jndi.name: persistence/testcontext]
I now want a dao class to have an entity manager injected by spring:
UserDao.class
#Repository
public class UserDao
{
#PersistenceContext(unitName = "testcontext")
private EntityManager entityManager;
}
I have component scanning and annotation config so both the #Repository and the #PersistenceContext annotation gets processed upon starting my application:
spring-servlet.xml
<context:component-scan base-package="com.company.project" />
<context:annotation-config/>
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/testcontext"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>
<tx:annotation-driven/>
The injection fails though, in two possible ways:
If I use #PersistenceContext(unitName = "testcontext"), the error is:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'testcontext' available
If I use #PersistenceContext, the error is:
Caused by: java.lang.NullPointerException
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:580)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:546)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:707)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:680)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354)
... 44 more
So I'm missing something in this configuration to tell the part of Spring that processes the #PersistenceContext annotation to look at either the entityManagerFactory bean that I declared in the spring-servlet.xml or just use the container's persistence unit directly. What do I need to add to achieve that?
I'm also a bit sketchy on the transactionmanager part. Does wildfly provide the transactionmanager or not? If it does, do I need to create a bean for it in Spring (will it pick up the one created by jboss or make its own one?)
I think you should double check you configuration setup against Spring official docs : https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#orm-jpa-setup-jndi .No, the transaction manager is provided by Spring. More info on this: https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction-strategies

Spring: How can I debug a BeanCreationNotAllowedException?

I am trying to add a new Spring bean to one of my projects. The bean is defined and created in another package like so:
#Configuration
public class UtilityBeans {
public static String MY_BEAN_NAME = "my.bean.name";
#Bean(name = MY_BEAN_NAME)
public MyUtilBeanClass getMyBeanClass() {
return new MyUtilBeanClass();
}
}
I use it in my other package like this:
#Configuration
#Import({
UtilityBeans.class
)}
...
#Resource(name = UtilityBeans.MY_BEAN_NAME)
private MyUtilBeanClass myUtilBeans;
During runtime I get:
ERROR
Caused by: org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'my.bean.name': Singleton bean creation not allowed while the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
...
The logs do not give me any useful information as the stack trace is all in Spring library. How can I find out what failed? Is it incorrect usage of resource or is it that the bean creation itself is wrong?
I am using Spring-4 with JDK8.
The issue here was that the bean was being created in 2 different points in my spring configuration due to some refactoring and the fix was to remove duplicate code. I had the same bean creation code:
#Bean(name = MY_BEAN_NAME)
public MyUtilBeanClass getMyBeanClass() {
return new MyUtilBeanClass();
}
... in another class I had half way refactored.
In this case my mistake was that I did not grep across all the log files being generated. The exceptions were being split and then buried into 2 different logs, one for a server start up and one for application runtime. The above exception was being posted to the application log. The other logs contained the relevant exception which stated that duplicate bean creation failed and the fix was to remove duplicate code.

Junit/Spring/Hibernate: How to specify an out of container datasource for Hibernate Session in Unit tests

I have an applicationContext.xml which defines a bean called "baseDataSource"
<bean id="baseDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="resourceRef" value="true"/>
<property name="jndiName" value="java:/MySQLDS20"/>
</bean>
Now ordinarily this is created fine within a jboss application using Spring and Hibernate. But when I try to instantiate this IOC container as part of unit testing via
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:WEB-INF/applicationContext.xml"})
I recieve this error:
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:87)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:201)
at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
I have thoroughly read the discussion here
http://forum.spring.io/forum/spring-projects/data/7448-problem-running-junit-test-with-jndi-datasource
But no answer there seems to either solve the issue or clearly explain what is going on. My question is this:
How do I maker this datasource work? I cannot copy and paste my applicationContext.xml into some testApplicationContext.xml just for the purpose of modifying this one single bean. What can I do to create the container and autowire in my junit tests without changing this bean or duplicating the xml config (my CTO will shoot me)
I cannot copy and paste my applicationContext.xml into some testApplicationContext.xml just for the purpose of modifying this one single bean.
You don't have to. You only have to create a configuration containing only an override for the datasource, then load both in your testcase.
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource>
</bean>
Then in your test case load this together with your actual file and the bean definition will override the one in your actual configuration.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:WEB-INF/applicationContext.xml", "applicationContext-test.xml"})
The latter should only contain beans you want to override/replace.
To inject a custom JNDI context into your unit test you could try the following:
#BeforeClass
public static void setUp() {
DataSource ds = null; // Construct data source manually
ds.setURL("..."); ds.setUser("..."); ds.setPassword("...");
SimpleNamingContextBuilder builder = null;
try {
builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
builder.bind("java:java:/MySQLDS20",ds);
} catch (NamingException e) {
logger.error(e);
}
}
This will expose the required JNDI name through the InitialContext.
But I would recommend you to extract the baseDataSource into a separate configuration file and then use a specific configuration file for your tests instead.
Like this:
In src/main/resources/applicationContext.xml:
<import resource="datasource.jndi.xml" />
JUnit Test Class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({
"classpath*:/datasource.test.xml",
})
public class MyTests
{
...
}
To inject a custom JNDI context into your unit test [Gregor Koukkoullis]
(this is a good method to integrate DataSource into JNDI, but you also need to init DataSource, then inject to JNDI Context)
You only have to create a configuration containing only an override for the datasource [M. Deinum]
(I think If you can define the datasource in new *.xml, so this method is easy to implements)
But David Williams need no copy *.xml, the purpose is very clearly, no change of configration, no change of source code, just test with JNDI.
below is my method:
1. search JNDI env in your remote Server.
2. with setup() method to init your Server JNDI properties.
then no change of configration, no change no test code, no addition datasource config, just add setup method to init remoter Server JNDI.

NoClassDefFoundError with spring cache and aspectj

I am getting this error in my spring webapp (spring 3.1), and I don't know why.
org.springframework.web.util.NestedServletException: Handler
processing failed; nested exception is java.lang.NoClassDefFoundError:
mypackage/TestCache$AjcClosure1
(the $AjcClosure1 is weird)
If I comment the annotation #Cacheable in the class below the error is gone.
public class TestCache {
#Cacheable(value ="myCache")
public List<String> getDummyList(){
Logger l = Logger.getLogger(this.getClass());
l.error("calling getDummyList");
ArrayList<String> foo = new ArrayList<String>();
foo.add("foo");
foo.add("bar");
return foo;
}
}
My controller class (simplified):
#Controller
#RequestMapping("/mypage")
public class MyController {
#RequestMapping
public String index(ModelMap model, Locale locale) {
TestCache tc = new TestCache();
...
}
}
Application Context (only cache part):
<cache:annotation-driven mode="aspectj"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml"/>
I tried proxy and aspectj mode (in proxy mode less error but the cache was doing nothing)
This web application was built initially with roo and use spring mvc and webflow. So there is quite a lot of xml in the applicationContext.xml or webmvc-config.xml (and I am not able to understand what some beans are doing).
I am running the wepapps in eclipse with m2e-wtp and the pom.xml is using the plug-in aspectj-maven-plugin (but no idea what it does)
It looks like the issue is related with aspectj, but I never used aspectJ.
If anyone spring/java/aspectj guru can explain me what is making this error and how I can make my cache working it would be awesome! (I could find only tutorial but no sample project using the cacheable annotation).
It seems that the problem comes from the fact that all the class$AjcClosure[n].class aren't published and the only way to do it is remove, the webapps, clean start and republish the webapp.
One problem (may not the one that causes the NoClassDefFoundError) is that you can use Spring Functions like #Cacheable only for Spring Beans. So if you create an class via new (and this class it not annotated by #Configurable) then this is a normal class and not a Spring bean. Therefore the annotation is ignored in proxy mode. -- May this will also result in this stange error in AspectJ mode, but I don't know.

#autowired #qualifier pointing to a service in a jar file application

I am using another application's service,since everything is already made and done.
My application is to use the interface class inside the application jar.
but something seem to be wrong when this code is called.
BeanFactory factory = new ClassPathXmlApplicationContext( "/Context-Controller.xml");
even if my Context-Controller.xml has this code
<context:component-scan base-package="com.package" />
My error.
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type
[com.package.ServiceIamUsing] is
defined: Unsatisfied dependency of
type [interface
com.package.ServiceIamUsing]: expected
at least 1 matching bean
this is how i autowired it on my applciation.
public class MyAppDao implements IMyAppDao {
#Autowired
#Qualifier("serviceIamUsing")
private ServiceIamUsing serviceIamUsing;
//More codes here
}
jay, try the following:
- eliminate the forward-slash "/"
- in your application context xml file, try to import the application context from your external jar file if it has any --> import resource="classpath*:/META-INF/spring/*.xml"
let me know if it does/doesn't work.
Is there, in fact, an instance of ServiceIamUsing in the jar that is also Spring-annotated (#Component, #Service, etc.)? It's possible this is the case, but I'd like to clarify.
If not, does the jar expose a Spring context file you can import, thus adding the additional beans to your context for autowiring?

Categories