In this post I want to share the most convenient way to test Spring beans using JUnit. The idea is to test using dependency injection techniques instead of performing a manual injection.
The versions I used to create this project are:
- Spring 3.1.1-RELEASE
- JUnit 4
- Maven 3
We just define a normal Spring bean in the test classpath.
The @RunWith(SpringJUnit4ClassRunner.class) tells JUnit to run JUnit using the SpringJUnit4ClassRunner class as the internal core. This allows the rest of the annotations (except for @Test) to work as expected. @ContextConfiguration brings up all the XML bean files in a context and we can dispone of those beans anytime in any test.
@Autowired injects a bean, if no @Qualifier specified, it is done BY TYPE; if @Qualifier is specified, it is injected BY BEAN ID. Let's see this in more detail:
In this example, we just have one bean of ar.com.pabloExample.services.MessageService type. So we can just put the @Autowired (no @Qualifier) and everything works as expected because it matches BY TYPE.
If we had the following beans file instead:
Then we cannot match only BY TYPE because we have now two beans of the same type. So, appart from @Autowired we must use @Qualifier with the bean id of the explicit bean to inject.
Just to keep in mind, here are two other ways of to use Spring beans while testing with old versions of JUnit and Spring. These ways are still being used in many enterprise applications:
The versions I used to create this project are:
- Spring 3.1.1-RELEASE
- JUnit 4
- Maven 3
Configuration files:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ar.com.pabloExample</groupId> <artifactId>spring-junit-example</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-junit-example</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.1.1.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.1.1.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> </dependencies> </project>
test-beans.xml
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <bean class="ar.com.pabloExample.services.MessageService" id="messageService"/> </beans>
We just define a normal Spring bean in the test classpath.
Creating the test
BeanInjectionNewWayTest
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/test-beans.xml" }) public class BeanInjectionNewWayTest { @Autowired @Qualifier("messageService") private MessageService messageService; @Test public void test() { messageService.printMessage(); } }
The @RunWith(SpringJUnit4ClassRunner.class) tells JUnit to run JUnit using the SpringJUnit4ClassRunner class as the internal core. This allows the rest of the annotations (except for @Test) to work as expected. @ContextConfiguration brings up all the XML bean files in a context and we can dispone of those beans anytime in any test.
@Autowired injects a bean, if no @Qualifier specified, it is done BY TYPE; if @Qualifier is specified, it is injected BY BEAN ID. Let's see this in more detail:
In this example, we just have one bean of ar.com.pabloExample.services.MessageService type. So we can just put the @Autowired (no @Qualifier) and everything works as expected because it matches BY TYPE.
If we had the following beans file instead:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <bean class="ar.com.pabloExample.services.MessageService" id="messageService"/> <bean class="ar.com.pabloExample.services.MessageService" id="messageService2"/> </beans>
Then we cannot match only BY TYPE because we have now two beans of the same type. So, appart from @Autowired we must use @Qualifier with the bean id of the explicit bean to inject.
Testing JUnit + Spring the old way!
Just to keep in mind, here are two other ways of to use Spring beans while testing with old versions of JUnit and Spring. These ways are still being used in many enterprise applications:
BeanInjectionOldWayTest
public class BeanInjectionOldWayTest extends AbstractSingleSpringContextTests { private MessageService messageService; @Override protected String[] getConfigLocations() { String[] locations = { "/test-beans.xml" }; return locations; } @Override public void onSetUp() { messageService = (MessageService) this.applicationContext.getBean("messageService"); } public void testInject() throws Exception { messageService.printMessage(); } }
BeanInjectionOldWay2Test
public class BeanInjectionOldWay2Test { private ApplicationContext applicationContext; private MessageService messageService; @Before public void init() { applicationContext = new ClassPathXmlApplicationContext("test-beans.xml"); messageService = (MessageService) applicationContext.getBean("messageService"); } @Test public void test() { messageService.printMessage(); } }
No comments:
Post a Comment