Automatic mock instantiation in a Spring JUnit test - spring

I have a Spring XML bean definition that I want to write integration tests for. The XML bean definition is part of a larger application context where several such files are included using <import>. Inside the definition, I reference several beans that are coming from other files.
For my integration test I would like to instantiate the definition standalone and use Mockito mocks for all other beans. Until now, I am using something like this:
FooIntegrationTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class FooIntegrationTest {
#Autowired private ClassUnderTest underTest;
#Autowired private MockedClass mock;
#Test
public void testFoo() {
}
}
FooIntegrationTest-context.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="part-to-test.xml" />
<bean id="mockedClassReferencedByName" class="org.mockito.Mockito" factory-method="mock" c:classToMock="SomeMockedClass" />
<bean class="org.mockito.Mockito" factory-method="mock" c:classToMock="OtherMockedClassReferencedByType" />
<bean class="org.mockito.Mockito" factory-method="mock" c:classToMock="MockedClass" />
...
</beans>
I would like to automate the rather tedious mocking section: Ideally, I would like to have all beans that are not found in the application context to be mocked automatically. The part-to-test.xml uses #Autowired as well as beans that are set by using name references. I only use XML bean definition files, and neither use #Configuration classes nor #Component annotations.
I have looked into how to use a custom context loader in #ContextConfiguration(loader=...), but I have not yet found an appropriate extension point for doing so. Sprinockito does not seem to adress this problem.
Is there some other project out there that already solves this problem? If not, where would I extend Spring to create the mocks automatically?

Here is a short article with a code example. A BeanDefinitionRegistryPostProcessor implementation generates a mock object for each lacking bean definition. The generation part is done with a MocksFactory, here is an example for such a factory.

Just in case anyone is still interested in this question, I have extended the code in the article mentioned by Yves Martin with inheritance, support for #Inject, etc... and created a Github project here: https://github.com/rinoto/spring-auto-mock

Related

spring: need for an example of using prototype bean in a web environment

I wonder how can I properly inject a prototype bean to a singleton one in a web app. Consider this example:
<bean id="order" class="com.foo.Order" scope="prototype"/>
<bean id="orderService" class="com.foo.OrderService">
<property name="userPreferences" ref="userPreferences"/>
</bean>
I thought of using getBean() but isn't that a way to make my code dependent to spring itself?
I need a short java code example to demonstrate how to inject an order bean in my OrderService singleton.
Thanks
You can use jsr-330 Providers, just put:
#Autowired
Provider<Order> orderProvider;
in your singleton bean, and then use the provider:
public Whatever yourMethod() {
Order order = orderProvider.get();
}

How to import Java-config class into XML-config so that both contexts have beans?

I have a project where I need to bootstrap #Configuration java-config classes into the XML configuration.
To do that, I'm reading that I also need to include the following bean definition (along with the bean definitions of the classes annotated with #Configuration).
<bean class="org.springframework.config.java.process.ConfigurationPostProcessor" />
But, I end up receiving the following error:
Caused by: java.lang.ClassNotFoundException: org.springframework.config.java.process.ConfigurationPostProcessor
I have to assume I'm missing a jar somewhere, but my various web searches hasn't resulted in an answer yet. Any help would be greatly appreciated. Thanks.
EDIT: Evidently, I was reading old documentation, which is no longer current. Let me back up. My project contains older XML-based configuration. The newer code is all using 'Java-config'. With that said, the contexts are apparently completely separate. I'd like to 'import' a java-config class into the XML configuration, so that both contexts have those particular beans. Does anyone know how I can do that?
This actually ended up being fairly simple. To get a Java-config bean definition into the xml-config, simply define the Java-config class as a bean within the XML-config. There are no extra jars necessary.
#Configuration
public class SomeJavaConfig {
#bean
... [bean definition]
}
inside the XML-config, you define this class as a bean.
<!-- needed to pick up the annotated java-config -->
<context:annotation-config />
<!-- Importing java-config class, which are annotated with #Configuration -->
<bean name="SomeJavaConfig" class="[fully qualified path].SomeJavaConfig" />
The XML-config, which may be part of a different context, now has all the bean definitions defined within the JavaConfig class.
UPDATED - to included Alan Franzoni's comment below in the answer.
Alternatively to annotation-config you can use component-scan. Then you do not have to include the Configuration Bean in XML:
<context:component-scan base-package="[fully qualified package path]" />
See Difference between <context:annotation-config> vs <context:component-scan> for more details.
Should be in:
spring-javaconfig-<version>.jar

aspectj and spring with aspectj-autoproxy

I've declared my aspects using the #Aspect annotation, but the advice does not seem to get applied. The aspect works in a few other projects that I have, and the key difference seems to be that the other projects are completely wired using annotations, and this particular project is xml wired. The only bean that is annotation wired is the Aspect. So I'm wondering if spring's aspectj support, when using aspectj-autoproxy is sensitive to order that the beans are defined in the xml.
For example, will beans declared after aspectj-autoproxy in xml be considered for AOP pointcuts?
EDIT:
I moved the <aop:aspectj-autoproxy /> until after all beans are created and still no luck.
Basically my code consists of:
#Component
#Aspect
public class SomeAspect {
#Pointcut("#annotation(MyAnnotation)")
public void isX() {}
#After("isX()")
public void XX() {
System.out.println("Called aspect");
}
}
And my controller has something like:
public class XController extends AbstractCommandController {
#MyAnnotation
public void handleX(...) {
// do stuff
}
#Override
protected void handle(...) {
return handleX(...);
}
}
And then the spring xml is:
<context:component-scan base-package="package.of.some.aspect" />
<aop:aspectj-autoproxy />
<!-- the rest of the beans below -->
<bean id="someController" class="..." />
My previous projects captured and loaded all beans via the component-scan. That's what's different this time.
EDIT2:
The other difference is that the other projects are using #Controller, and #RequestMethod. And in this case I'm using a derived class of AbstractCommmandController. I'm wondering if this applies:
http://forum.springsource.org/archive/index.php/t-46637.html
Namely that I can't apply advice to any method except handleRequest().
EDIT3:
My latest try is to override handleRequest() and apply my annotation there. Under the assumption that when spring proxies my controller it will see the annotation and apply the advice, since it's calling through the public, externally called method. This still doesn't work.
I see that you are calling the method handleX directly from another method in the same class. This will not respect the annotiation, as the work of processing AOP annotations is done by a JDK proxy that wraps your class and exposes the same interfaces.
It's possible that you can work around this by using CGLIB instead of JDK proxies, but in my experience, the most reliable solution is just not to rely on any AOP annotations for methods called internally.

Could annotation based and xml based configuration be used together in spring 2.5?

I've been working on a project where controllers have been written extending Controller classes. Could I configure and use the POJO based Controllers as well (using #Controller) in the same application?
Many thanks
Thanks jamestastic and skaffman, its working all fine now :)
Below are the lines needed to to be addeded to the web configuration file to have them working together:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" ...line1
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context ...line2
http://www.springframework.org/schema/context/spring-context-2.5.xsd"> ...line3
<context:annotation-config/> ...line4
<context:component-scan base-package="myPackage"/> ...line5
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> ...line6
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> ...line7
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> ...line8
</beans>
I was too lazy to not to add line 8 in my main application.
Many thanks
Absolutely. You can mix them together as much as you choose. DispatcherServlet should recognise both old-style and new-style controllers together in the same app.
Yes you can. You'll need to include the Spring JavaConfig project library, as annotation configuration was not part of the 2.5 core.
Here is an example I wrote a while back comparing Google Guice with Spring. Toward the bottom (look for #ImportXml), I show how you can combine Spring XML configuration with annotation configuration. The configuration looks like this:
#Configuration
#ImportXml(locations = "classpath:com/earldouglas/guicespringjc/spring/config.xml")
public class XmlSpringConfiguration {
}
See the Spring Reference regarding combining XML and Annotation configuration. This is from the documentation for Spring 3, but it should still apply (with perhaps minor changes in class names and paths from the old Spring JavaConfig project).
In Spring >= 3.0 use #ImportResource annotation
#Configuration
#ImportResource({ "classpath:/path/to/spring.xml", })
public class AppConfig {
}

Configuring a spring project

My question is : from basic which are the necessary jars that should required in Spring and how could we configure Spring project ?
Go to Spring home page and download Spring (Here, i am using 2.5.x version)
After installing, put the following jar in your classpath
<SPRING_HOME>/dist/spring.jar
Here goes a single bean
package br.com.introducing.Hello;
public class Hello {
private String message;
// getter's and setter's
}
...
Write a single xml to configure your beans as follows
// app.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="hello" class="br.com.introducing.Hello">
<property name="message" value="What do you want ?"/>
</bean>
</beans>
Put your app.xml in root classpath
And your psvm
public static void main(String [] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("app.xml");
Hello hello = (Hello) appContext.getBean("hello");
hello.getMessage(); // outputs What do you want ?
}
UPDATE
What is the role of the applicationContext.xml
When using getBean method, it behaves like a Factory pattern. Something like
public class ApplicationContext {
Map wiredBeans = new HashMap();
public static Object getBean(String beanName) {
return wiredBeans.get(beanName);
}
}
As said by Spring in Action book
It is a general-purpose factory, creating and dipensing many types of bean.
But, There is more
Allows you load files
You can publish events
It supports i18n (i18n stands for internationalization)
Suppose here goes messages.properties (root of the classpath)
// messages.properties
messsageCode=What do you want ?
To enable i18n, You must define a bean called messageSource to get advantage of our resource, as follows
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages"/>
</bean>
</beans>
Now, you can use it
appContext.getMessage("messsageCode", null, null); // outputs What do you want ?
Usually, we do not need to define all of our beans in xml file. You can use annotations (Additional settings needed to enable component scanning) instead of xml, Something like
package br.com.introducing.Hello;
#Component
public class Hello {
private String message;
// getter's and setter's
}
Component annotation says:
Spring, i am a general-purpose bean which can be retrieved through application context
A good resource about Spring is either Spring in Action book or Spring documentation
Advice: read carefully
You can have a look at the article on understanding the webapplicationcontexts and other xml config files in spring
Think this can help you in getting the configurations related to basic spring MVC with ease
You can also use Maven to create and manage projects. You can get an idea about Maven and how to start from here
A directory structure will be created by Maven and there will be a pom.xml inside your project directory. You can mention all dependencies in this file. Eg: for using spring, you can mention the dependency as follows,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.3</version>
</dependency>
If you are using Eclipse as IDE, you need to execute the following command,
mvn eclipse:eclipse
This will create a .project file. You can now import the project into Eclipse IDE and start coding your application.
For beginners, Spring reference documentation and books like Spring in Action and Spring Recipes are very useful

Resources