Spring团队认为测试是企业软件开发中不可或缺的一部分。
依赖注入的主要好处之一,是你的代码的运行环境或其他子系统, 不太可能有任何隐藏的依赖关系。这使得单元测试中,所测试的对象可以被简单实例化,并设置在单元测试代码中的依赖。您可以使用mock对象(联同其他许多有价值的测试技术)来测试你的代码隔离。如果你遵循了 Spring 的架构建议,就会发现清晰的层次和代码组件将大大方便单元测试。例如,您将能够测试服务层对象的存根或DAO接口,可以在没有访问任何持久性数据的同时,运行单元测试。
真正的单元测试运行起来通常都非常迅速,因为没有运行时基础设施的设置,即数据库,ORM工具,或其他什么。因此,作为你的开发方法论的一部分,强调真正的单元测试将提高您的生产力。
但是,同样重要的是能够执行一些集成测试,使您能够测试的东西,如:
•Spring IoC 容器上下文的正确配置。
•数据访问使用 ADO.NET 或 ORM 工具。这将包括这样的事情,如SQL的正确性 /或NHibernate的XML映射文件。
Spring.NET 支持两种测试环境,对于 NUnit 测试的支持定义在文件 Spring.Testing.NUnit .dll 中,这里使用了 NUnit 2.5.1。对于 MSUnit 的支持定义在 Spring.Testing.Microsoft.dll 中。
在这些程序集中提供了 NUnit 和 MSTest 的父类 AbstractDependencyInjectionSpringContextTests,来支持使用 Spring 容器中的集成测试。
这些超类提供了以下功能:
• Spring的 IoC 容器可以在测试用例的执行之间被缓存。
• 测试实例非常非常透明的依赖注入(这是好的)。
• 适合集成测试的事务管理(这更加爽)。
• 一系列 Spring 特定的继承的实例变量,真的很有用时的集成测试。
上下文管理
Spring.Testing.NUnit 和 Spring.Testing.Microsoft命名空间提供了一致的加载 Spring 上下文和缓存加载的能力。同样Spring 对于测试缓存上下文是很重要的,因为如果你是一个大的项目上工作,启动时间可能会成为一个问题 - 不是因为Spring自身的开销,但因为由Spring容器初始化的对象将采取实例化。例如,一个 50-100 的 NHibernate映射文件项目可能需要10-20秒载入映射文件,并招致之前运行每一个测试案例,在每一个测试用例,会导致降低了整体的测试效率。
为了解决这个问题,AbstractDependencyInjectionSpringContextTests 作为父类,子类必须实现提供上下文定义文件的位置:
protected abstract string[] ConfigLocations { get; }
这个属性方法的实现必须提供一个数组,包含用于配置应用程序的元数据 XML 配置资源的位置。这与普通的 App.config/ Web.config或其他部署配置中指定的地点几乎是相同的。
默认情况下,一旦加载,配置文件中设置将在每个测试用例中重用。这样设置的成本只会产生一次(每个测试fixture),接下来的测试执行就会快得多。在有的情况下,测试可配置的位置,需要重新加载 - 例如,通过改变'脏', 对象的定义或应用对象的状态 - 你可以调用SetDirty()方法,AbstractDependencyInjectionSpringContextTests 造成测试用例重新载入配置重建,然后再执行下一个测试案例的应用程序上下文。
测试用例的依赖注入
当AbstractDependencyInjectionSpringContextTests(子类)加载应用程序的情况下,他们可以选择性地配置通过 Setter 注入你的测试类的实例。所有您需要做的就是定义实例变量和相应的setter方法。AbstractDependencyInjectionSpringContextTests 会自动在 ConfigLocations 属性中指定的配置文件的设置中找到相应的对象。
考虑下面的情况,我们有一个类,名字叫 HibernateTitleDao说,执行数据访问逻辑,取得 Title 域对象。
我们要编写集成测试,测试以下几个方面:
•Spring配置,基本上是有关与 HibernateTitleDao 对象的配置一切正确的,现在呢?
•Hibernate 映射文件的配置,是一切正确映射和正确的延迟加载在地方设置?
•逻辑与HibernateTitleDao; 配置这个类的实例执行如预期?
/// <summary> /// 测试类从 AbstractDependencyInjectionSpringContextTests 派生一下 /// 这个类的 ConfigLocations 提供了用来指定配置文件位置的机制 /// AbstractDependencyInjectionSpringContextTests 使用自动类型装配机制 /// </summary> [TestFixture] public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests { // this instance will be (automatically) dependency injected // 用于注入的字段 private HibernateTitleDao titleDao; // a setter method to enable DI of the 'titleDao' instance variable // 注入的属性 public HibernateTitleDao HibernateTitleDao { set { titleDao = value; } } [Test] public void LoadTitle() { Title title = this.titleDao.LoadTitle(10); Assert.IsNotNull(title); } // specifies the Spring configuration to load for this test fixture // 配置文件加载的位置 protected override string[] ConfigLocations { get { return new String[] { "assembly://MyAssembly/MyNamespace/daos.xml" }; } } }
与此相关的配置参数如下:
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<!-- this object will be injected into the HibernateTitleDaoTests class -->
<object id="titleDao" type="Spring.Samples.HibernateTitleDao, Spring.Samples">
<property name="sessionFactory" ref="sessionFactory"/>
</object>
<object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate">
<!-- dependencies elided for clarity -->
</object>
</objects>
AbstractDependencyInjectionSpringContextTests 类使用类型自动装配。因此,如果你有同一类型的多个对象的定义,你不能依靠这种方法对那些特定的对象。在这
在这种情况下,您可以使用继承的ApplicationContext 实例变量,并明确查找使用(例如)applicationContext.GetObject(“titleDao”)的一个显式调用。