Spring Unit/Intergration Testing setup - java

I didn't write unit or integration testing but now I am trying. I am having a hard time setting up the environment.
I have my application context under WEB-INF/applicationContext*.xml
and in my applicationContext.xml, it has a reference to a properties file for DB user/pass, LDAP host, etc
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/spring-config/dev.properties</value>
</list>
</property>
</bean>
I have another properties for log4j config (diff config for DEV/Staging/Production). ${webapp.root} is defined in web.xml
<!-- log4j setting -->
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>${webapp.root}/${log4j.properties.location}</value>
</list>
</property>
</bean>
And now I am trying to put the following in a test class.
#Override
protected String[] getConfigLocations() {
return new String[]{
"file:trunk/code/web/WEB-INF/applicationContext.xml",
};
}
This references my xml correctly, but all the properties are screwed up.
I want to know the following:
Is there a way to set up in the test class properly? If not, should I move these classes?
How can I set up Log4j if there is a reference to webroot which only exist in a container?!
What is the best practice of Spring config location?
Please Advise
Thanks

This blogpost of mine describes the basic steps to achieve your goal.
Note that the unit tests shouldn't know that you have a webapp-root - they are usually run without any servlet container started. So place the alternative config files in the test packages and try.

For unit testing you should not be using the Spring application context. You should be testing all your spring beans and controllers individually as they are the individual units within the system. As they are POJOs it is easy to wire everything together programatically in your test case code. The also solves issues such as the location of the logging properties file as you can programatically specify a different path that does not rely on the webroot property.
The testing chapter in the Spring Reference provides a good overview of how to approach unit and integration testing of applications that use Spring. It also provides details of the various support classes that Spring provides to help with writing unit and integration tests.

You could use annotations to reference the necessary configuration from the tests, like this:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
#ContextConfiguration(locations = {
"file:../WebService/src/main/resources/application-context.xml",
"file:../ServiceLayer/src/test/resources/ServiceLayer-dao-test-context.xml" })
public class MyTest {
// class body...
}

Related

Spring-Boot: Jmx annotation not working in library

I have a Spring-Boot application that just have a simple rest controller. On this controller, I added the jmx annotations #ManagedResource and #ManagedOperation and it is working fine. It is correctly exposed in Jmx.
This application depends on a "global-commons" library to share many basic functionality to all of our modules.
But if I add the same annotations to a class in this library, it is ignored!
And before you ask, yes the library is imported with the latest change.
There is no error or warning message in the logs.
I am configuring all my beans using an xml file. Both classes are beans defined in the same file.
One is a #RestController. The other one is a simple utility class.
Any idea?
Make sure the classes from the global-commons library as managed by Spring. As long as none of the classes in the library are managed by Spring, the annotions don't have any effect.
I found the problems:
The bean that was not working was defined as an "inner" bean:
<bean id="imMetrics" class="com.imetrik.global.common.metrics.ImGlobalMetrics" init-method="init">
...
<property name="reporterList">
<util:list>
<bean id="jmxReporter" class="com.imetrik.global.common.metrics.reporters.ImJmxReporter">
<property name="registryId" value="metricRegistry1"/>
<property name="durationUnit" value="SECONDS"/>
<property name="rateUnit" value="SECONDS"/>
<property name="domain" value="com.imetrik.global.metric"/>
</bean>
</util:list>
</property>
</bean>
The annotated beans is "jmxReporter".
But if I put it outside as a normal "first level" bean and use a reference instead, it is working.
But it is annoying! Is there a way to make it work even as a inner beans?

Annotation to set a specific system property in Spring 3.0?

I have a set of unit tests. Some will use dataSource, others will want to use hsqlbDataSource. This datasource is not a wired bean into my unit tests/code, but is transitively used via templates and transaction managers. Therefore I intend to use bean defs like this:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDataSource"
cache="true" resource-ref="true" lookup-on-startup="false"
proxy-interface="javax.sql.DataSource" />
<jee:jndi-lookup id="hsqlbDataSource" jndi-name="jdbc/myDataSource"
cache="true" resource-ref="true" lookup-on-startup="false"
proxy-interface="javax.sql.DataSource" />
<bean id="qmat-das-jdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"
c:dataSource-ref="${test.datasource:dataSource}" />
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
<property name="dataSource" ref="${test.datasource:dataSource}"/>
</bean>
I want for my unit tests (there are many of them, of course) to pick and choose which datasource to use. Ideally what makes sense to me is for each unit test to have an annotation which sets the system property to override the default datasouce with its own. Is there an elegant way to achieve that without property files, but just set the java property via an annotation?
With an annotation it's not possible with out-of-the-box functionality, but have a look at Spring 3 profiles as it allows to activate/deactivate groups of beans.
The beans can be activated with system properties or via code. This code could be put in a test superclass to activate the test-only beans:
springContext.getEnvironment().setActiveProfiles("test")

Using spring as configurator

I have a server application. Now I'm using Spring not only to inject dependencies, but also to config my application. Something like this:
<bean id="server" class="foo.bar.Server">
<property name="host" value="${config.host}"/>
<property name="someBean">
<ref bean="someBean"/>
</property>
</bean>
My colleague sad that configuring application in Spring is not obvious and we should avoid this. I see logic in his words, because Spring is for dependence injection and server port is not dependency, isn't it? But for me configuring application is Spring is very convenient and obvious. Is my colleague right?
Configuring in Spring is simple, clear and maintainable.
This way you can easily create several instances with different properties.

Changing scope of many Spring beans during tests

I'm running tests using spring (SpringJUnit4ClassRunner and #ContextConfiguration). The tests are run in parallel.
Some of my beans are singleton, and I would like to change them to be in scope "thread" of the tests. I want each test to have its own instance of the bean.
I've managed to it by having an applicationContext.xml file and a applicationTestContext.xml file which is used for tests.
In the applicationTestContext.xml I define those beans with scope "thread".
The problem with this is that everytime we add a new bean of that type, we'll have to add it to both applicationContext.xml and applicationTestContext.xml which is pretty annoying.
Is there a way to do it with less boilerplate?
Gather up all the beans whose scope you want to customize and put them in a separate bean config file, included from both applicationContext and applicationTestContext, e.g.
<import resource="customScopedBeans.xml"/>
Then use a placeholder for the scope
<bean class="com.Foo" scope="${threadOrSingleton}" />
and declare the property differently in the parent config file.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>threadOrSingleton=thread</value>
</property>
</bean>

Correct usage Of LOG4J in Spring Framework Via DI

I am trying to use Log4j as part of the Spring Framework,
as far as i understand through the use of a an appropriate bean
the system is supposed to map a singleton instance accessible in the code
while mapping the logging depth automatically to the class
Similar to the normal use of Log4J as in
Logger log = Logger.getLogger(getClass());
i have been using the following Spring bean definition
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>conf\log4j.xml</value>
</list>
</property>
</bean>
But i am unable to map this bean to a specific member in a given class
nor am i able to use it through #autowired
Please let me know if there are any better ways to integrate Log4j and Spring
Best Regards
Mark
The short answer to your question is that log4j is not DI friendly.
The Log4jConfigurer.initLogging() method has a void return value, so there's nothing to inject. The idea is that you call that method, which bootstraps log4j, and then you use the Log4j API as usual (using Logger.getLogger(getClass())).
You generally wouldn't configure Log4jConfigurer as a Spring bean, though, but more usually you'd invoke it directly from your own code during application startup.
If this is a webapp, then Spring provides alternatives to Log4jConfigurer that are better suited to that environment (Log4jWebConfigurer, Log4jConfigListener).
Incidentally, 2 years ago I filed a feature request to allow loggers to be autowired, and it's finally been marked as fix for Spring 3.1. Horray.

Categories

Resources