1.1.1 和Spring的集成
Unitils 也提供了对Spring框架的支持。Sping的一个基本远侧就是你的对象应该被设计成容易测试的,即使没有Spring或者其他容器。There are times however, when it can be useful to work with object structures that are wired by the Spring container.
Unitils支持Spring的特性如下:
- 管理ApplicationContext配置
注入Spring beans到单元测试
使用Hibernate SessionFactory 配置
在Spring配置中引用Unitls 数据源
1.1.1.1 ApplicationContext配置
你只需要在类,方法或者属性上用注解@SpringApplicationContext,并且指明需要的Spring配置文件,既可以容易的装载application context 。例如:
public class UserServiceTest extends UnitilsJUnit4 {
@SpringApplicationContext({"spring-config.xml", "spring-test-config.xml"})
private ApplicationContext applicationContext;
}
这样就可以装载Spring-config.xml 和 spring-test-config.xml文件并建立新的ApplicationContext,并将会注入对应的属性。在setter方法上也可以使用注解,而不仅仅是属性上。
父类也会被扫描,检查是否有@SpringApplicationContect注解存在。如果发现的话,这些配置文件会首先被加载。
这样就可都能通过扩展的特殊配置类覆盖父类的配置。例如:
public class UserServiceTest extends UnitilsJUnit4 {
@SpringApplicationContext({"spring-config.xml", "spring-test-config.xml"})
private ApplicationContext applicationContext;
}
在上面的例子,将即哪里一个新的ApplicationContext,首先加载spring-beans.xml,然后是extra-spring-beans.xml配置。然后application context被注入到注解的属性。
注意在这个例子里,一个新的application context被建立了。这是必须的因为有扩展的配置文件被指明了。Unitils会尽量重用application context 。在下面的例子里,没有扩展的文件被加载,因为相同的appliction context实例被重用了。
@SpringApplicationContext("spring-beans.xml")
public class BaseServiceTest extends UnitilsJUnit4 {
}
public class UserServiceTest extends BaseServiceTest {
@SpringApplicationContext
private ApplicationContext applicationContext;
}
public class UserGroupServiceTest extends BaseServiceTest {
@SpringApplicationContext
private ApplicationContext applicationContext;
}
在公共的父类BaseServiceTest中指明了配置文件,ApplicationContext会被建立一次,然后被子类重用。
既然加载一次application context的操作是比较麻烦的,那么尽量重用他对你的测试性能是有很大好处的。
1.1.1.1.1 Programmatic configuration
编程式配置也是可能的,你可以注解一个方法,这个方法没有参数或者有一个List<String>作为参数,方法会返回一个ConfigrableApplicationContext的实例。If a List<String> parameter is specified, all locations of the @SpringApplicationContext annotations that would otherwise be used to create a new instance will be passed to the method.
The result of this method should be an instance of an application context for which the refresh() method was not yet invoked. This important, since it allows Unitils to perform extra configuration such as adding some BeanPostProcessors, which is no longer possible once refresh is invoked. In case of aClassPathXmlApplicationContext this can easily be achieved by passing false as value for the refresh parameter of the constructor:
@SpringApplicationContext
public ConfigurableApplicationContext createApplicationContext(List<String> locations) {
return new ClassPathXmlApplicationContext(Arrays.asList(locations), false);
}
@SpringApplicationContext
public ConfigurableApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext(Arrays.asList("spring-beans.xml","extra-spring-beans.xml"), false);
}
1.1.1.2 Injection of Spring beans
Once you've configured an ApplicationContext, Spring beans are injected into fields / setters annotated with @SpringBean, @SpringBeanByType or@SpringBeanByName. Following example shows 3 ways to get a UserService bean instance from the application context:
Spring bean的注入
一旦你配置了application context,Spring bean 会注入到那些使用了@springBean,@SpringBeanByType或者@SpringBeanByName的方法属性中,下面例子展现了3中从application context中去的UserService Bean的方式。
@SpringBean("userService")
private UserService userService;
@SpringBeanByName
private UserService userService;
@SpringBeanByType
private UserService userService;
使用@SpringBean,你会从Application Context中得到一个名字严格匹配的Bean。@SpringBeanByName有相同的效果,但是现在字段的名字被用作唯一的标识。
如果使用@SpringBeanByType,则会依据字段的类型查找application context 。这种情况下,这可都能是UserService类或者他的子类。如果没有查到,或者查到多个结果,系统会抛出异常。
The same annotations can be used on setter methods. For example:
@SpringBeanByType
public void setUserService(UserService userService) {
this.userService = userService;
}
1.1.1.3 配置测试数据库
在数据库测试单元我们展示怎么为你的测试获得并安装一个数据源。使用hibernate测试单元描述怎么为你的测试配置hibernate.在spring中,这些通常被放在spring的配置文件。加入你的application容易使用了如下类似的文件application-config.xml:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost/sample"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="annotatedClasses"> <list> <value>org.unitils.sample.User</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect hibernate.show_sql=true </value> </property> </bean>
第一个bean定义了链接应用数据库的数据源,第二个bean配置了hibernate 的 SessionFactory 并使用上面的数据源。
如果我们的测试里需要连接数据库,通常一个测试用的spring配置文件会像下面的内容一样:
<bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean" />
With this configuration, Spring will make use of the DataSource configured in Unitils. Refer to the configuration chapter for more information on how to configure a test DataSource.
Unitils automatically detects the SessionFactory configured in Spring: all integration features Unitils offers for Hibernate also work when using Spring. Thehibernate mapping test will therefore also work as follows:
对于这个配置,Srping会只用Unitils中配置的数据源。可以参考 the configuration chapter查找更多信息来查看怎么配置一个测试数据源。
Unitils自动探测Spring中配置的SessionFactory:Unitils提供的所有集成hibernate的特性也可以使用在Spring。hibernate mapping test 因此也可以如下配置:
@SpringApplicationContext({"application-config.xml", "test-ds-config.xml"})
public class HibernateMappingTest extends UnitilsJUnit4 {
@Test
public void testMappingToDatabase() {
HibernateUnitils.assertMappingWithDatabaseConsistent();
}
}