亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄 搜索
前言 簡介 概覽 使用場景 Spring 2.0和 2.5的新特性 簡介 控制反轉(zhuǎn)(IoC)容器 新的bean作用域 更簡單的XML配置 可擴展的XML編寫 Annotation(注解)驅(qū)動配置 在classpath中自動搜索組件 面向切面編程(AOP) 更加簡單的AOP XML配置 對@AspectJ 切面的支持 對bean命名pointcut( bean name pointcut element)的支持 對AspectJ裝載時織入(AspectJ load-time weaving)的支持 中間層 在XML里更為簡單的聲明性事務(wù)配置 對Websphere 事務(wù)管理的完整支持 JPA 異步的JMS JDBC Web層 Spring MVC合理的默認值 Portlet 框架 基于Annotation的控制器 Spring MVC的表單標簽庫 對Tiles 2 支持 對JSF 1.2支持 JAX-WS支持 其他 動態(tài)語言支持 增強的測試支持 JMX 支持 將Spring 應(yīng)用程序上下文部署為JCA adapter 計劃任務(wù) 對Java 5 (Tiger) 支持 移植到Spring 2.5 改變 支持的JDK版本 Spring 2.5的Jar打包 XML配置 Deprecated(淘汰)的類和方法 Apache OJB iBATIS Hibernate JDO UrlFilenameViewController 更新的樣例應(yīng)用 改進的文檔 核心技術(shù) IoC(控制反轉(zhuǎn))容器 簡介 基本原理 - 容器和bean 容器 配置元數(shù)據(jù) 實例化容器 XML配置元數(shù)據(jù)的結(jié)構(gòu) 多種bean bean的命名 bean的別名 實例化bean 用構(gòu)造器來實例化 使用靜態(tài)工廠方法實例化 使用實例工廠方法實例化 使用容器 依賴 注入依賴 構(gòu)造器注入 構(gòu)造器參數(shù)解析 構(gòu)造器參數(shù)類型匹配 構(gòu)造參數(shù)索引 Setter注入 一些例子 依賴配置詳解 直接變量(基本類型、Strings類型等。) idref元素 引用其它的bean(協(xié)作者) 內(nèi)部bean 集合 集合的合并 強類型集合(僅適用于Java5+) Nulls XML配置文件的簡寫及其他 XML-based configuration metadata shortcuts 使用p名稱空間配置屬性 組合屬性名稱 使用depends-on 延遲初始化bean 自動裝配(autowire)協(xié)作者 將bean排除在自動裝配之外 依賴檢查 方法注入 Lookup方法注入 自定義方法的替代方案 Bean的作用域 Singleton作用域 Prototype作用域 Singleton beans和prototype-bean的依賴 其他作用域 初始化web配置 Request作用域 Session作用域 global session作用域 作用域bean與依賴 選擇創(chuàng)建代理的類型 自定義作用域 創(chuàng)建自定義作用域 使用自定義作用域 定制bean特性 生命周期回調(diào) 初始化回調(diào) 析構(gòu)回調(diào) 缺省的初始化和析構(gòu)方法 組合生命周期機制 在非web應(yīng)用中優(yōu)雅地關(guān)閉Spring IoC容器 了解自己 BeanFactoryAware BeanNameAware bean定義的繼承 容器擴展點 用BeanPostProcessor定制bean 使用BeanPostProcessor的Hello World示例 RequiredAnnotationBeanPostProcessor示例 用BeanFactoryPostProcessor定制配置元數(shù)據(jù) PropertyPlaceholderConfigurer示例 PropertyOverrideConfigurer示例 使用FactoryBean定制實例化邏輯 The ApplicationContext BeanFactory 還是 ApplicationContext? 利用MessageSource實現(xiàn)國際化 事件 底層資源的訪問 ApplicationContext在WEB應(yīng)用中的實例化 粘合代碼和可怕的singleton 以J2EE RAR文件的形式部署Spring ApplicationContext 基于注解(Annotation-based)的配置 @Autowired 基于注解的自動連接微調(diào) CustomAutowireConfigurer @Resource @PostConstruct 與 @PreDestroy 對受管組件的Classpath掃描 @Component和更多典型化注解 自動檢測組件 使用過濾器自定義掃描 自動檢測組件的命名 為自動檢測的組件提供一個作用域 用注解提供限定符元數(shù)據(jù) 注冊一個LoadTimeWeaver 資源 簡介 Resource接口 內(nèi)置 Resource 實現(xiàn) UrlResource ClassPathResource FileSystemResource ServletContextResource InputStreamResource ByteArrayResource ResourceLoader接口 ResourceLoaderAware 接口 把Resource作為屬性來配置 Application context 和Resource 路徑 構(gòu)造application context 創(chuàng)建 ClassPathXmlApplicationContext 實例 - 簡介 Application context構(gòu)造器中資源路徑的通配符 Ant風(fēng)格的pattern 潛在的可移植性 classpath*: 前綴 其他關(guān)于通配符的說明 FileSystemResource 說明 校驗,數(shù)據(jù)綁定,BeanWrapper,與屬性編輯器 簡介 使用Spring的Validator接口進行校驗 從錯誤代碼到錯誤信息 Bean處理和BeanWrapper 設(shè)置和獲取屬性值以及嵌套屬性 內(nèi)建的PropertyEditor實現(xiàn) 注冊用戶自定義的PropertyEditor 使用PropertyEditorRegistrars 使用Spring進行面向切面編程(AOP) 簡介 AOP概念 Spring AOP的功能和目標 AOP代理 @AspectJ支持 啟用@AspectJ支持 聲明一個切面 聲明一個切入點(pointcut) 切入點指示符(PCD)的支持 組合切入點表達式 共享通用切入點定義 示例 聲明通知 前置通知 后置通知(After returning advice) 異常通知(After throwing advice) 最終通知(After (finally) advice) 環(huán)繞通知 通知參數(shù)(Advice parameters) 訪問當(dāng)前的連接點 傳遞參數(shù)給通知 確定參數(shù)名 處理參數(shù) 通知順序 引入(Introduction) 切面實例化模型 例子 基于Schema的AOP支持 聲明一個切面 聲明一個切入點 聲明通知 前置通知 后置通知 異常通知 最終通知 環(huán)繞通知 通知參數(shù) 通知順序 引入 切面實例化模型 Advisor 例子 AOP聲明風(fēng)格的選擇 Spring AOP還是完全用AspectJ? Spring AOP中使用@AspectJ還是XML? 混合切面類型 代理機制 理解AOP代理 以編程方式創(chuàng)建@AspectJ代理 在Spring應(yīng)用中使用AspectJ 在Spring中使用AspectJ進行domain object的依賴注入 @Configurable對象的單元測試 Working with multiple application contexts Spring中其他的AspectJ切面 使用Spring IoC來配置AspectJ的切面 在Spring應(yīng)用中使用AspectJ加載時織入(LTW) 第一個例子 切面 'META-INF/aop.xml' 相關(guān)類庫(JARS) Spring配置 特定環(huán)境的配置 通用Java應(yīng)用 Tomcat WebLogic 更多資源 Spring AOP APIs 簡介 Spring中的切入點API 概念 切入點運算 AspectJ切入點表達式 便利的切入點實現(xiàn) 靜態(tài)切入點 正則表達式切入點 屬性驅(qū)動的切入點 動態(tài)切入點 控制流切入點 切入點的超類 自定義切入點 Spring的通知API 通知的生命周期 Spring里的通知類型 攔截環(huán)繞通知 前置通知 異常通知 后置通知 引入通知 Spring里的Advisor API 使用ProxyFactoryBean創(chuàng)建AOP代理 基礎(chǔ) JavaBean屬性 基于JDK和CGLIB的代理 對接口進行代理 對類進行代理 使用“全局”通知器 簡化代理定義 使用ProxyFactory通過編程創(chuàng)建AOP代理 操作被通知對象 使用“自動代理(autoproxy)”功能 自動代理bean定義 BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator AbstractAdvisorAutoProxyCreator 使用元數(shù)據(jù)驅(qū)動的自動代理 使用TargetSource 熱交換目標源 池化目標源 原型目標源 ThreadLocal目標源 定義新的Advice類型 更多資源 測試 簡介 單元測試 Mock對象 JNDI Servlet API Portlet API 單元測試支持類 通用工具類 Spring MVC 集成測試 概覽 使用哪個支持框架 通用目標 上下文管理及緩存 測試fixtures依賴注入 事務(wù)管理 集成測試支持類 JDBC測試支持 常用注解 JUnit 3.8遺留支持 上下文管理及緩存 測試fixture依賴注入 字段級別(Field Level)注入 事務(wù)管理 JUnit 3.8 遺留支持類 Java 5+ 專有支持 使用注解的事務(wù)相關(guān)測試 JPA支持類 Spring TestContext Framework 主要的抽象 上下文管理和緩存 測試fixture的依賴注入 事務(wù)管理 TestContext支持類 JUnit 3.8支持類 JUnit 4.4支持類 定制JUnit 4.4運行器 TestNG支持類 TestContext框架注解支持 PetClinic示例 更多資源 中間層數(shù)據(jù)訪問 事務(wù)管理 簡介 動機 關(guān)鍵抽象 使用資源同步的事務(wù) 高層次方案 低層次方案 TransactionAwareDataSourceProxy 聲明式事務(wù)管理 理解Spring的聲明式事務(wù)管理實現(xiàn) 第一個例子 回滾 為不同的bean配置不同的事務(wù)語義 <tx:advice/> 有關(guān)的設(shè)置 使用 @Transactional @Transactional 有關(guān)的設(shè)置 事務(wù)傳播 required RequiresNew Nested 通知事務(wù)操作 結(jié)合AspectJ使用 @Transactional 編程式事務(wù)管理 使用TransactionTemplate 指定事務(wù)設(shè)置 使用PlatformTransactionManager 選擇編程式事務(wù)管理還是聲明式事務(wù)管理 與特定應(yīng)用服務(wù)器集成 IBM WebSphere BEA WebLogic Oracle OC4J 常見問題的解決方法 對一個特定的 DataSource 使用了錯誤的事務(wù)管理器 更多的資源 DAO支持 簡介 一致的異常層次 一致的DAO支持抽象類 使用JDBC進行數(shù)據(jù)訪問 簡介 選擇一種工作模式 Spring JDBC包結(jié)構(gòu) 利用JDBC核心類控制JDBC的基本操作和錯誤處理 JdbcTemplate類 一些示例 查詢(SELECT) 更新(INSERT/UPDATE/DELETE) 其他操作 JdbcTemplate 的最佳實踐 NamedParameterJdbcTemplate類 SimpleJdbcTemplate類 DataSource接口 SQLExceptionTranslator接口 執(zhí)行SQL語句 執(zhí)行查詢 更新數(shù)據(jù)庫 獲取自動生成的主鍵 控制數(shù)據(jù)庫連接 DataSourceUtils類 SmartDataSource接口 AbstractDataSource類 SingleConnectionDataSource類 DriverManagerDataSource類 TransactionAwareDataSourceProxy類 DataSourceTransactionManager類 NativeJdbcExtractor JDBC批量操作 使用JdbcTemplate進行批量操作 使用SimpleJdbcTemplate進行批量操作 通過使用SimpleJdbc類簡化JDBC操作 使用SimpleJdbcInsert插入數(shù)據(jù) 使用SimpleJdbcInsert來獲取自動生成的主鍵 指定SimpleJdbcInsert所使用的字段 使用SqlParameterSource提供參數(shù)值 使用SimpleJdbcCall調(diào)用存儲過程 聲明SimpleJdbcCall使用的參數(shù) 如何定義SqlParameters 使用SimpleJdbcCall調(diào)用內(nèi)置函數(shù) 使用SimpleJdbcCall返回的ResultSet/REF Cursor 用Java對象來表達JDBC操作 SqlQuery類 MappingSqlQuery類 SqlUpdate類 StoredProcedure類 SqlFunction類 參數(shù)和數(shù)據(jù)處理的基本原則 為參數(shù)設(shè)置SQL類型信息 處理BLOB 和 CLOB對象 在IN語句中傳入一組參數(shù)值 處理復(fù)雜類型的存儲過程調(diào)用 使用ORM工具進行數(shù)據(jù)訪問 簡介 Hibernate 資源管理 在Spring容器中創(chuàng)建 SessionFactory The HibernateTemplate 不使用回調(diào)的基于Spring的DAO實現(xiàn) 基于Hibernate3的原生API實現(xiàn)DAO 編程式的事務(wù)劃分 聲明式的事務(wù)劃分 事務(wù)管理策略 容器資源 vs 本地資源 在應(yīng)用服務(wù)器中使用Hibernate的注意事項 JDO 建立PersistenceManagerFactory JdoTemplate和JdoDaoSupport 基于原生的JDO API實現(xiàn)DAO 事務(wù)管理 JdoDialect Oracle TopLink SessionFactory 抽象層 TopLinkTemplate and TopLinkDaoSupport 基于原生的TopLink API的DAO實現(xiàn) 事務(wù)管理 iBATIS SQL Maps 創(chuàng)建SqlMapClient 使用 SqlMapClientTemplate 和 SqlMapClientDaoSupport 基于原生的iBATIS API的DAO實現(xiàn) JPA 在Spring環(huán)境中建立JPA LocalEntityManagerFactoryBean 從JNDI中獲取 EntityManagerFactory LocalContainerEntityManagerFactoryBean Tomcat(5.0以上)加載時的織入配置 使用VM代理的全局加載時織入 上下文范圍內(nèi)的加載時織入配置 處理多持久化單元 JpaTemplate 和 JpaDaoSupport 基于原生的JPA實現(xiàn)DAO 異常轉(zhuǎn)化 事務(wù)管理 JpaDialect The Web Web MVC framework Web框架 概述 與其他MVC實現(xiàn)框架的集成 Spring Web MVC框架的特點 DispatcherServlet 控制器 AbstractController 和 WebContentGenerator 其它的簡單控制器 MultiActionController 命令控制器 處理器映射(handler mapping) BeanNameUrlHandlerMapping SimpleUrlHandlerMapping 攔截器(HandlerInterceptor) 視圖與視圖解析 視圖解析器(ViewResolver) 視圖解析鏈 重定向(Rediret)到另一個視圖 RedirectView redirect:前綴 forward:前綴 本地化解析器 AcceptHeaderLocaleResolver CookieLocaleResolver SessionLocaleResolver LocaleChangeInterceptor 使用主題 簡介 如何定義主題 主題解析器 Spring對分段文件上傳(multipart file upload)的支持 介紹 使用MultipartResolver 在表單中處理分段文件上傳 使用Spring的表單標簽庫 配置 form標簽 input標簽 checkbox標簽 checkboxes標簽 radiobutton標簽 radiobuttons標簽 password標簽 select標簽 option標簽 options標簽 textarea標簽 hidden標簽 errors標簽 處理異常 慣例優(yōu)先原則(convention over configuration) 對控制器的支持:ControllerClassNameHandlerMapping 對模型的支持:ModelMap(ModelAndView) 對視圖的支持:RequestToViewNameTranslator 基于注解的控制器配置 建立dispatcher實現(xiàn)注解支持 使用@Controller定義一個控制器 使用@RequestMapping映射請求 使用@RequestParam綁定請求參數(shù)到方法參數(shù) 使用@ModelAttribute提供一個從模型到數(shù)據(jù)的鏈接 使用@SessionAttributes指定存儲在會話中的屬性 自定義WebDataBinder初始化 使用@InitBinder自定義數(shù)據(jù)綁定 配置一個定制的WebBindingInitializer 更多資源 集成視圖技術(shù) 簡介 JSP和JSTL 視圖解析器 'Plain-old' JSPs versus JSTL 'Plain-old' JSP與JSTL 幫助簡化開發(fā)的額外的標簽 Tiles 需要的資源 如何集成Tiles UrlBasedViewResolver類 ResourceBundleViewResolver類 SimpleSpringPreparerFactory 和 SpringBeanPreparerFactory Velocity和FreeMarker 需要的資源 Context 配置 創(chuàng)建模板 高級配置 velocity.properties FreeMarker 綁定支持和表單處理 用于綁定的宏 簡單綁定 表單輸入生成宏 輸入域 選擇輸入域 重載HTML轉(zhuǎn)碼行為并使你的標簽符合XHTML XSLT 寫在段首 Bean 定義 標準MVC控制器代碼 把模型數(shù)據(jù)轉(zhuǎn)化為XML 定義視圖屬性 文檔轉(zhuǎn)換 小結(jié) 文檔視圖(PDF/Excel) 簡介 配置和安裝 文檔視圖定義 Controller 代碼 Excel視圖子類 PDF視圖子類 JasperReports 依賴的資源 配置 配置ViewResolver 配置View 關(guān)于報表文件 使用 JasperReportsMultiFormatView 構(gòu)造ModelAndView 使用子報表 配置子報表文件 配置子報表數(shù)據(jù)源 配置Exporter的參數(shù) 集成其它Web框架 簡介 通用配置 JavaServer Faces DelegatingVariableResolver FacesContextUtils Struts ContextLoaderPlugin DelegatingRequestProcessor DelegatingActionProxy ActionSupport Classes Tapestry 注入 Spring 托管的 beans 將 Spring Beans 注入到 Tapestry 頁面中 組件定義文件 添加抽象訪問方法 將 Spring Beans 注入到 Tapestry 頁面中 - Tapestry 4.0+ 風(fēng)格 WebWork 更多資源 Portlet MVC框架 介紹 控制器 - MVC中的C 視圖 - MVC中的V Web作用范圍的Bean DispatcherPortlet ViewRendererServlet 控制器 AbstractController 和 PortletContentGenerator 其它簡單的控制器 Command控制器 PortletWrappingController 處理器映射 PortletModeHandlerMapping ParameterHandlerMapping PortletModeParameterHandlerMapping 增加 HandlerInterceptors HandlerInterceptorAdapter ParameterMappingInterceptor 視圖和它們的解析 Multipart文件上傳支持 使用 PortletMultipartResolver 處理表單里的文件上傳 異常處理 Portlet應(yīng)用的部署 整合 使用Spring進行遠程訪問與Web服務(wù) 簡介 使用RMI暴露服務(wù) 使用RmiServiceExporter暴露服務(wù) 在客戶端鏈接服務(wù) 使用Hessian或者Burlap通過HTTP遠程調(diào)用服務(wù) 為Hessian和co.配置DispatcherServlet 使用HessianServiceExporter暴露你的bean 在客戶端連接服務(wù) 使用Burlap 對通過Hessian或Burlap暴露的服務(wù)使用HTTP Basic認證 使用HTTP調(diào)用器暴露服務(wù) Exposing the service object 在客戶端連接服務(wù) Web Services 使用JAX-RPC暴露基于servlet的web服務(wù) 使用JAX-RPC訪問web服務(wù) 注冊JAX-RPC Bean映射 注冊自己的JAX-RPC 處理器 使用JAX-WS暴露基于servlet的web服務(wù) 使用JAX-WS暴露單獨web服務(wù) 使用Spring支持的JAX-WS RI來暴露服務(wù) 使用JAX-WS訪問web服務(wù) 使用XFire來暴露Web服務(wù) JMS 服務(wù)端配置 客戶端配置 對遠程接口不提供自動探測實現(xiàn) 在選擇這些技術(shù)時的一些考慮 Enterprise Java Beans (EJB) 集成 簡介 訪問EJB 概念 訪問本地的無狀態(tài)Session Bean(SLSB) 訪問遠程SLSB Accessing EJB 2.x SLSBs versus EJB 3 SLSBs 使用Spring提供的輔助類實現(xiàn)EJB組件 EJB 2.x base classes EJB 3 注入攔截 JMS (Java Message Service) 簡介 使用Spring JMS JmsTemplate 連接工廠 目的地管理 消息偵聽容器 SimpleMessageListenerContainer DefaultMessageListenerContainer ServerSessionMessageListenerContainer 事務(wù)管理 發(fā)送消息 使用消息轉(zhuǎn)換器 SessionCallback 和 ProducerCallback 接收消息 同步接收 異步接收 - 消息驅(qū)動的POJO SessionAwareMessageListener接口 MessageListenerAdapter 事務(wù)中的消息處理 JCA消息端點的支持 JMS命名空間支持 JMX 介紹 將Bean暴露為JMX 創(chuàng)建MBeanServer 重用原有的MBeanServer 延遲初始化的MBean MBean的自動注冊 控制注冊行為 控制Bean的管理接口 MBeanInfoAssembler接口 使用源碼級元數(shù)據(jù) 使用JDK 5.0的注解 源代碼級的元數(shù)據(jù)類型 AutodetectCapableMBeanInfoAssembler接口 用Java接口定義管理接口 使用MethodNameBasedMBeanInfoAssembler 控制Bean的ObjectName 從Properties讀取Properties 使用MetadataNamingStrategy <context:mbean-export/>元素 JSR-160連接器 服務(wù)器端連接器 客戶端連接器 基于Burlap/Hessian/SOAP的JMX 通過代理訪問MBean 通知 為通知注冊監(jiān)聽器 發(fā)布通知 更多資源 JCA CCI 簡介 配置CCI 連接器配置 在Spring中配置ConnectionFactory 配置CCI連接 使用一個 CCI 單連接 使用Spring的 CCI訪問支持 記錄轉(zhuǎn)換 CciTemplate類 DAO支持 自動輸出記錄生成 總結(jié) 直接使用一個CCI Connection接口和Interaction接口 CciTemplate 使用示例 建模CCI訪問為操作對象 MappingRecordOperation MappingCommAreaOperation 自動生成輸出記錄 總結(jié) MappingRecordOperation 使用示例 MappingCommAreaOperation 使用示例 事務(wù) Spring郵件抽象層 簡介 使用Spring郵件抽象 MailSender 和 SimpleMailMessage 的基本用法 使用 JavaMailSender 和 MimeMessagePreparator 使用MimeMessageHelper 發(fā)送附件和嵌入式資源(inline resources) 附件 內(nèi)嵌資源 使用模板來創(chuàng)建郵件內(nèi)容 一個基于Velocity的示例 Spring中的定時調(diào)度(Scheduling)和線程池(Thread Pooling) 簡介 使用OpenSymphony Quartz 調(diào)度器 使用JobDetailBean 使用 MethodInvokingJobDetailFactoryBean 使用triggers和SchedulerFactoryBean來包裝任務(wù) 使用JDK Timer支持類 創(chuàng)建定制的timers 使用 MethodInvokingTimerTaskFactoryBean類 最后:使用TimerFactoryBean來設(shè)置任務(wù) SpringTaskExecutor抽象 TaskExecutor接口 TaskExecutor類型 使用TaskExecutor 動態(tài)語言支持 介紹 第一個示例 定義動態(tài)語言支持的bean 公共概念 <lang:language/> 元素 Refreshable bean 內(nèi)置動態(tài)語言源文件 理解dynamic-language-backed bean上下文中的構(gòu)造器注入 JRuby beans Groovy beans 通過回調(diào)定制Groovy對象 BeanShell beans 場景 Spring MVC控制器的腳本化 Validator的腳本化 Bits and bobs AOP - 通知腳本化bean 作用域 更多的資源 注解和源代碼級的元數(shù)據(jù)支持 簡介 Spring的元數(shù)據(jù)支持 注解 @Required Spring中的其它@Annotations Jakarta Commons Attributes集成 元數(shù)據(jù)和Spring AOP自動代理 基本原理 聲明式事務(wù)管理 示例程序 演示案例 介紹 使用動態(tài)語言實現(xiàn)的Spring MVC控制器 構(gòu)建與部署 使用SimpleJdbcTemplate和@Repository實現(xiàn)DAO 域?qū)ο?/a> Data Access Object 構(gòu)建 XML Schema-based configuration Introduction XML Schema-based configuration Referencing the schemas The util schema <util:constant/> Setting a bean property or constructor arg from a field value <util:property-path/> Using <util:property-path/> to set a bean property or constructor-argument <util:properties/> <util:list/> <util:map/> <util:set/> The jee schema <jee:jndi-lookup/> (simple) <jee:jndi-lookup/> (with single JNDI environment setting) <jee:jndi-lookup/> (with multiple JNDI environment settings) <jee:jndi-lookup/> (complex) <jee:local-slsb/> (simple) <jee:local-slsb/> (complex) <jee:remote-slsb/> The lang schema The jms schema The tx (transaction) schema The aop schema The context schema <property-placeholder/> <annotation-config/> <component-scan/> <load-time-weaver/> <spring-configured/> <mbean-export/> The tool schema The beans schema Setting up your IDE Setting up Eclipse Setting up IntelliJ IDEA Integration issues XML parsing errors in the Resin v.3 application server Extensible XML authoring Introduction Authoring the schema Coding a NamespaceHandler Coding a BeanDefinitionParser Registering the handler and the schema 'META-INF/spring.handlers' 'META-INF/spring.schemas' Using a custom extension in your Spring XML configuration Meatier examples Nesting custom tags within custom tags Custom attributes on 'normal' elements Further Resources spring-beans-2.0.dtd spring.tld Introduction The bind tag The escapeBody tag The hasBindErrors tag The htmlEscape tag The message tag The nestedPath tag The theme tag The transform tag spring-form.tld Introduction The checkbox tag The checkboxes tag The errors tag The form tag The hidden tag The input tag The label tag The option tag The options tag The password tag The radiobutton tag The radiobuttons tag The select tag The textarea tag Spring 2.5開發(fā)手冊中文化項目 聲明 致謝 參與人員 項目歷程
文字

8.3.?集成測試

8.3.1.?概覽

能夠無需部署到你的應(yīng)用服務(wù)器上或連接其它企業(yè)架構(gòu)就實現(xiàn)集成測試是非常重要的。這可以讓你來進行以下測試:

  • 正確配置Spring IoC 容器上下文。

  • 使用JDBC或ORM工具的數(shù)據(jù)訪問??赡馨ㄈ鏢QL腳本,Hibernate query,JPA 實體映射等的正確性驗證。

Spring框架提供集成測試的一流支持,相關(guān)類打包在spring-test.jar類庫中。在這個類庫中,你可以找到org.springframework.test包,有很多方便使用Spring容器進行集成測試的類,而且同時不依賴應(yīng)用服務(wù)器或其它部署環(huán)境。這些測試會比單元測試慢,但會比Cactus(譯者注:Apache測試服務(wù)端Java代碼的工具http://jakarta.apache.org/cactus/index.html )測試或依靠部署到一個應(yīng)用服務(wù)器上來進行遠程測試要快捷的多。

在2.5版本之前,Spring已經(jīng)提供了面向JUnit 3.8的單元測試支持. 在2.5版本中, Spring 提供了單元和集成測試支持 Spring TestContext框架。 它是實際測試框架的混合體,因此能夠幫助在多個測試環(huán)境包括JUnit 3.8,JUnit 4.4, TestNG等中進行測試。 注意Spring TestContext框架需要Java 5+支持.

8.3.2.?使用哪個支持框架

Spring團隊推薦使用Spring TestContext框架 來進行所有新的單元測試和集成測試,以包括ApplicationContext或需要事務(wù)管理的情況。 但如果你開發(fā)在Java5之前的環(huán)境上,就需要繼續(xù)使用JUnit 3.8遺留支持. 另外,顯式 JPA集成測試支持 依賴于shadow class載入來進行JPA類測試(class instrumentation)目前只能與JUnit 3.8遺留支持相容。 如果你要測試的JPA提供者不需要class instrumentation,就推薦使用TestContext框架。

8.3.3.?通用目標

Spring集成測試支持框架提供了一些通用目標,包括:

  • 跨越各個測試案例執(zhí)行期的Spring IoC容器緩存。

  • 測試fixture實例的依賴注入 (這很爽)。

  • 適合集成測試的事務(wù)管理(這更加爽)。

  • Spring特有的支持類在編寫集成測試時真的很有用。

下面的章節(jié)具體描述每一個目標并提供指向特定支持框架的信息的鏈接。

8.3.3.1.?上下文管理及緩存

Spring集成測試支持框架提供了ApplicationContext的持久化載入和這些上下文的緩存機制。 對已載入上下文的緩存是很重要的,因為如果你是在一個大型的項目中,啟動時間會成為一個問題――不是因為Spring本身的開銷, 而是因為靠Spring容器來初始化的對象需要很長時間。比如一個有50-100 Hibernate映射文件的項目可能需要10-20秒來載入映射文件, 而每次單一測試fixture的每個單一測試前都要這樣的時間開銷,減慢了整體的測試進度進而降低效率。

測試類通常會提供一個數(shù)組來包含XML配置元數(shù)據(jù)的資源路徑――通常是classpath――來配置應(yīng)用。這通常和web.xml或其它部署描述中指定的配置路徑是相同或相近的。

默認情況下,一旦載入,ApplicationContext將在每次測試中重用。 這樣啟動的開銷將只需要一次(每個測試fixture),接下來的測試執(zhí)行就會快得多。 在一些少見的會“污染”應(yīng)用上下文的案例中需要重新載入―― 例如,改變一個bean定義或應(yīng)用對象的狀態(tài)―― Spring的測試支持提供了在執(zhí)行下一個測試前讓測試fixture重新載入配置并重建應(yīng)用上下文的機制。

上下文管理和緩存使用:

  • JUnit 3.8遺留支持

  • TestContext框架

8.3.3.2.?測試fixtures依賴注入

當(dāng)Spring集成測試支持框架載入你的應(yīng)用上下文時,它們能通過依賴注入選擇性配置測試類實例。 這提供了一個方便的機制來使用預(yù)先在應(yīng)用上下文中配置的bean來搭建測試fixture。 很大的好處就是你可以在各種測試場景中重用應(yīng)用上下文(例如配置Spring管理的對象圖, 事務(wù)代理DataSource等),從而能避免為單個的測試案例重復(fù)進行測試fixture搭建。

作為例子,考慮一個場景:我們有一個HibernateTitleDao類來實現(xiàn)數(shù)據(jù)訪問邏輯,假設(shè)是Title域?qū)ο蟆N覀兿M帉憸y試所有以下方面的集成測試:

  • Spring配置: 最基本的,是否所有與HibernateTitleDao bean相關(guān)的配置都是正確和存在的?

  • Hibernate映射配置文件: 是否所有映射都是正確的并且lazy-loading設(shè)置也到位了?

  • HibernateTitleDao邏輯:是否類的已配置示例的實現(xiàn)與預(yù)期相同?

測試fixtures依賴注入使用:

  • JUnit 3.8 遺留支持

  • TestContext框架

8.3.3.3.?事務(wù)管理

訪問實際數(shù)據(jù)庫的測試的一個通常問題是對持久化狀態(tài)的影響。 即使你使用開發(fā)數(shù)據(jù)庫,狀態(tài)的改變也可能影響后面的測試。而且很多操作 ―― 如插入或修改持久化數(shù)據(jù) ―― 不能在事務(wù)外完成(或驗證)。

Spring集成測試支持框架滿足了這些需求。默認情況下,對每次測試它們會創(chuàng)建并回滾事務(wù)。 你編寫代碼可以假定事務(wù)已經(jīng)存在。如果你在測試中調(diào)用事務(wù)代理對象,它們將根據(jù)配置的事務(wù)語義正常響應(yīng)。 另外,如果測試方法在事務(wù)內(nèi)刪除了選定表的數(shù)據(jù),這個事務(wù)會默認回滾,數(shù)據(jù)庫也將回到測試執(zhí)行前的狀態(tài)。 事務(wù)支持通過在測試應(yīng)用上下文中定義的PlatformTransactionManager bean提供。

如果你希望事務(wù)被提交 ―― 不常見,但可能你希望特定的測試插入或修改數(shù)據(jù)庫 ―― Spring集成測試支持框架 可以通過調(diào)用一個繼承下來的鉤子(Hook)方法或聲明特定注解來讓事務(wù)提交而不是回滾。

事務(wù)管理使用:

  • JUnit 3.8 遺留支持

  • TestContext框架

8.3.3.4.?集成測試支持類

Spring集成測試支持框架提供了幾個abstract支持類來簡化編寫集成測試。 這些測試基類提供了定義良好的測試框架鉤子,比如方便的變量實例和方法,來訪問以下對象:

  • ApplicationContext: 用來進行顯式bean查找或整體測試上下文狀態(tài)。

  • JdbcTemplateSimpleJdbcTemplate: 用來查詢并確認狀態(tài)。 例如,你可能需要在創(chuàng)建對象并通過ORM工具持久化到數(shù)據(jù)庫中的測試案例運行前后進行查詢,以確認數(shù)據(jù)在數(shù)據(jù)庫中存在了。 (Spring將確保查詢在同一個事務(wù)范圍內(nèi)運行。) 你需要通知ORM工具來'flush'變化以確保正常工作, 例如使用Hibernate Session接口的flush()方法。

你經(jīng)常會提供一個應(yīng)用范圍的超類來為多個集成測試提供有用的實例變量。

支持類:

  • JUnit 3.8遺留支持

  • TestContext框架

8.3.4.?JDBC測試支持

org.springframework.test.jdbc包含有SimpleJdbcTestUtils類,它 是一個基于Java5的JDBC相關(guān)工具方法集,用來簡化標準數(shù)據(jù)庫測試場景。注意AbstractTransactionalJUnit38SpringContextTests, AbstractTransactionalJUnit4SpringContextTests, 和AbstractTransactionalTestNGSpringContextTests 提供了簡便的方法來內(nèi)部代理到SimpleJdbcTestUtils

8.3.5.?常用注解

Spring框架在org.springframework.test.annotation 包中提供了常用的Spring特定的注解集,如果你在Java5或以上版本開發(fā),可以在測試中使用它。

  • @IfProfileValue

    提示一下,注解測試只針對特定的測試環(huán)境。 如果配置的ProfileValueSource類返回對應(yīng)的提供者的名稱, 這個測試就可以啟動。這個注解可以應(yīng)用到一個類或者單獨的方法。

    @IfProfileValue(name="java.vendor", value="Sun Microsystems Inc.")
    public void testProcessWhichRunsOnlyOnSunJvm() {
        // some logic that should run only on Java VMs from Sun Microsystems
    }

    同時@IfProfileValue可配置一個列表 (使用OR 語義) 來在JUnit環(huán)境中獲得TestNG的測試組支持。 看下面的例子:

    @IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"})
    public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
        // some logic that should run only for unit and integration test groups
    }
  • @ProfileValueSourceConfiguration

    類級別注解用來指定當(dāng)通過@IfProfileValue注解獲取已配置的profile值時使用何種ProfileValueSource。 如果@ProfileValueSourceConfiguration沒有在測試中聲明,將默認使用SystemProfileValueSource

    @ProfileValueSourceConfiguration(CustomProfileValueSource.class)
    public class CustomProfileValueSourceTests {
        // class body...
    }
  • @DirtiesContext

    在測試方法上出現(xiàn)這個注解時,表明底層Spring容器在該方法的執(zhí)行中被“污染”,從而必須在方法執(zhí)行結(jié)束后重新創(chuàng)建(無論該測試是否通過)。

    @DirtiesContext
    public void testProcessWhichDirtiesAppCtx() {
        // some logic that results in the Spring container being dirtied
    }
  • @ExpectedException

    表明被注解方法預(yù)期在執(zhí)行中拋出一個異常。預(yù)期異常的類型在注解中給定。如果該異常的實例在測試方法執(zhí)行中被拋出, 則測試通過。同樣的如果該異常實例沒有在測試方法執(zhí)行時拋出,則測試失敗。

    @ExpectedException(SomeBusinessException.class)
    public void testProcessRainyDayScenario() {
        // some logic that should result in an Exception being thrown
    }
  • @Timed

    表明被注解的測試方法必須在規(guī)定的時間區(qū)間內(nèi)執(zhí)行完成(以毫秒記)。如果測試執(zhí)行時間超過了規(guī)定的時間區(qū)間,測試就失敗了。

    注意該時間區(qū)間包括測試方法本身的執(zhí)行,任何重復(fù)測試(參見 @Repeat),還有任何測試fixture的set uptear down時間。

    @Timed(millis=1000)
    public void testProcessWithOneSecondTimeout() {
        // some logic that should not take longer than 1 second to execute
    }
  • @Repeat

    表明被注解的測試方法必須重復(fù)執(zhí)行。執(zhí)行的次數(shù)在注解中聲明。

    注意重復(fù)執(zhí)行范圍包括包括測試方法本身的執(zhí)行,以及任何測試fixture的set uptear down

    @Repeat(10)
    public void testProcessRepeatedly() {
        // ...
    }
  • @Rollback

    表明被注解方法的事務(wù)在完成后是否需要被回滾。 如果true,事務(wù)將被回滾,否則事務(wù)將被提交。 使用@Rollback接口來在類級別覆寫配置的默認回滾標志。

    @Rollback(false)
    public void testProcessWithoutRollback() {
        // ...
    }
  • @NotTransactional

    出現(xiàn)該注解表明測試方法必須在事務(wù)中執(zhí)行。

    @NotTransactional 
    public void testProcessWithoutTransaction() {
        // ...
    }

注解支持:

  • JUnit 3.8遺留支持: 所有上面列舉的注解都被支持,但必須AbstractAnnotationAwareTransactionalTests類聯(lián)合使用,以保證這些注解能起作用。

  • TestContext框架: 支持上面列舉的所有注解,而且提供了額外的TestContext特定注解 (例如@ContextConfiguration、@BeforeTransaction等等)。 注意,但是一些注解只有與JUnit聯(lián)合使用時(例如,基于SpringJUnit4ClassRunner 或JUnit 3.8以及JUnit 4.4的測試類)。 詳細內(nèi)容參見TestContext框架章節(jié)。

8.3.6.?JUnit 3.8遺留支持

Spring JUnit 3.8 遺留支持類打包在org.springframework.test包中。 這個包提供了有用的JUnit TestCase超類, 擴展它可以在容器外集成測試中引入Spring ApplicationContext類或在測試方法級別獲得事務(wù)支持。

8.3.6.1.?上下文管理及緩存

AbstractSingleSpringContextTests為基于JUnit 3.8的測試案例提供了上下文管理和緩存支持。 它暴露了一個protected方法來給子類覆寫以提供上下文定義文件的路徑:

protected String[] getConfigLocations()

這個方法的實現(xiàn)必須提供包含XML配置元數(shù)據(jù)的資源路徑 ―― 通常是類路徑 ―― 的一個數(shù)組。 這和在web.xml或其它部署配置中的資源路徑是相同的或基本相同的。 作為可選方案,你也可以覆寫下面的方法。詳細內(nèi)容參見相關(guān)JavaDoc。

protected String[] getConfigPaths()
protected String getConfigPath()

默認情況下,一旦配置文件被載入就會在每個測試案例中重用。 這樣構(gòu)建的開銷只會產(chǎn)生一次(每個測試fixture),然后后面的測試執(zhí)行會快速的多。 在較少的情況下測試可能“污染”應(yīng)用上下文,需要重新載入 ―― 例如, 改變一個bean定義或應(yīng)用對象狀態(tài) ―― 你可以調(diào)用AbstractSingleSpringContextTests類中的 setDirty()方法來讓測試fixture在執(zhí)行下一個測試案例時重新載 AbstractAnnotationAwareTransactionalTests類, 你可以使用@DirtiesContext來對測試方法進行注解以達到同樣的效果。

8.3.6.2.?測試fixture依賴注入

當(dāng)AbstractDependencyInjectionSpringContextTests類(及其子類)載入你的應(yīng)用上下文時, 它們可以通過Setter注入選擇性配置你的測試類實例。你需要做的僅僅是定義實例變量和相應(yīng)的setter方法。 AbstractDependencyInjectionSpringContextTests將在getConfigLocations()方法定義的配置文件集中自動查找相應(yīng)對象。

假定這樣一個場景,我們有一個HibernateTitleDao類(在通常目標章節(jié)詳述)。 讓我們看基于JUnit 3.8 的測試類實現(xiàn)本身(我們很快將看看配置本身)。

public final class HibernateTitleDaoTests extends AbstractDependencyInjectionSpringContextTests  {

    // this instance will be (automatically) dependency injected    
    private HibernateTitleDao titleDao;

    // a setter method to enable DI of the 'titleDao' instance variable
    public void setTitleDao(HibernateTitleDao titleDao) {
        this.titleDao = titleDao;
    }

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }

    // specifies the Spring configuration to load for this test fixture
    protected String[] getConfigLocations() {
        return new String[] { "classpath:com/foo/daos.xml" };
    }

}

這個文件被getConfigLocations()方法指定(比如,"classpath:com/foo/daos.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">

    <!-- this bean will be injected into the HibernateTitleDaoTests class -->
    <bean id="titleDao" class="com.foo.dao.hibernate.HibernateTitleDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <!-- dependencies elided for clarity -->
    </bean>

</beans>

AbstractDependencyInjectionSpringContextTests類使用按類型自動裝配。 因此如果你有多個bean定義是相同的類型,就不能在這些bean中使用這種方法。 這種情況下,你可以使用繼承的applicationContext實例變量并實現(xiàn)顯式的查找(比如), 調(diào)用applicationContext.getBean("titleDao")方法。

如果你不希望在測試案例中使用依賴注入,只要不聲明任何public setter方法就可以簡單實現(xiàn)。 作為替代的,你可以擴展AbstractSpringContextTests - 在org.springframework.test 包中的JUnit 3.8集成測試支持類層次的根 - 它僅僅包含了一些載入Spring上下文的簡單方法,而且不在測試fixture中使用依賴注入。

8.3.6.2.1.?字段級別(Field Level)注入

如果不管何種原因,你的測試fixture中沒有setter方法,Spring可以對protected字段進行依賴注入。 下面是前面使用字段級注入示例的新版本(Spring XML文件無需改變,僅僅需要改變測試fixture)。

public final class HibernateTitleDaoTests extends AbstractDependencyInjectionSpringContextTests  {

    public HibernateTitleDaoTests() {
        // switch on field level injection
        setPopulateProtectedVariables(true);
    }

    // this instance will be (automatically) dependency injected
    protected HibernateTitleDao titleDao;

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }

    // specifies the Spring configuration to load for this test fixture
    protected String[] getConfigLocations() {
        return new String[] { "classpath:com/foo/daos.xml" };
    }

}

在字段注入的情況下,不能使用自動裝配:protected 實例變量被作為已配置的Spring容器的bean 查找名。

8.3.6.3.?事務(wù)管理

AbstractTransactionalSpringContextTests類 依賴于應(yīng)用上下文中定義的PlatformTransactionManager bean。 名字是無關(guān)緊要的,因為使用了按類型自動裝配.

通常你會擴展其子類AbstractTransactionalDataSourceSpringContextTests。 這個類也需要在應(yīng)用上下文中有一個DataSource bean定義(同樣可以是任意名稱)。 它創(chuàng)建一個JdbcTemplate實例變量,可以用來方便的查詢和刪除選定表的內(nèi)容( 請記住默認情況下事務(wù)將被回滾,因而這樣做是安全的)。

如果你希望編程式提交事務(wù) ―― 不常見但對于特殊的插入數(shù)據(jù)庫的測試很有用 ―― 你可以調(diào)用繼承自AbstractTransactionalSpringContextTests類的setComplete() 方法。 這將使事務(wù)提交而不是回滾。作為可替代的,如果你在Java 5或更高環(huán)境中開發(fā)擴展AbstractAnnotationAwareTransactionalTests類, 你可以使用@Rollback(false)來注解測試方法,以通過配置獲得相同的效果。

通過調(diào)用endTransaction()方法,這里可以在測試案例完成時中止一個事務(wù)。 默認將回滾事務(wù),除非前面調(diào)用了setComplete()方法。 這個特性當(dāng)你希望測試‘?dāng)噙B接’的 數(shù)據(jù)對象行為是很有用,比如事務(wù)外的web或遠程使用的Hibernate映射實體。 通常懶加載錯誤只有通過UI測試發(fā)現(xiàn)。如果你調(diào)用endTransaction()方法 可以保證JUnit測試時UI操作的正確性。

8.3.6.4.?JUnit 3.8 遺留支持類

當(dāng)你擴展 AbstractTransactionalDataSourceSpringContextTests類時,你將需要訪問下面protected 實例變量:

  • applicationContext(ConfigurableApplicationContext): 繼承自AbstractSingleSpringContextTests類。使用它可以進行顯式bean查找或測試整個的上下文狀態(tài)。

  • jdbcTemplate: 繼承自AbstractTransactionalDataSourceSpringContextTests類,用于查詢已確認狀態(tài)。 例如,應(yīng)用代碼要創(chuàng)建一個對象,然后使用ORM工具將其持久化,這時你想在測試代碼執(zhí)行前后對其進行查詢,以確定數(shù)據(jù)是否插入到數(shù)據(jù)庫中(Spring會保證該查詢運行在相同事務(wù)內(nèi))。你需要告訴你的ORM工具‘清空’其改變以正確完成任務(wù),例如,使用HibernateSession接口的flush()方法。

8.3.6.5.?Java 5+ 專有支持

8.3.6.5.1.?使用注解的事務(wù)相關(guān)測試

在上述常用注解之外, org.springframework.test.annotation包也有一個抽象 JUnit TestCase類來提供注解驅(qū)動的集成測試支持。

AbstractAnnotationAwareTransactionalTests類擴展了AbstractTransactionalDataSourceSpringContextTests類, 并通過擴展fixture引入一些(Spring專有)的注解。AbstractAnnotationAwareTransactionalTests 支持所有常用注解章節(jié)中列舉的注解, 而且包括Spring的@Transactional注解,以顯式配置事務(wù)語義。

8.3.6.5.2.?JPA支持類

org.springframework.test.jpa包提供了基于Java 持久化API(JPA)的測試支持類。

  • AbstractJpaTests是一個方便的JPA相關(guān)測試的支持類, 它提供了和AbstractTransactionalDataSourceSpringContextTests相同的功能和即使在進行JPA規(guī)范需要的性能測試時也相同的性能。 它暴露了一個EntityManagerFactory接口和一個共享的EntityManager接口。 需要注入一個EntityManagerFactory接口, 以及通過超類獲得DataSource接口和JpaTransactionManager接口。

  • AbstractAspectjJpaTests類是AbstractJpaTests的子類, 它激活了AspectJ 的裝載期織入并能夠讓AspectJ指定一個自定義的aop.xml文件路徑。

8.3.7.?Spring TestContext Framework

Spring TestContext Framework (在org.springframework.test.context包中) 提供了一般的、注解驅(qū)動的單元和集成測試支持,它對使用的測試框架不做要求,可以使用JUnit 3.8、JUnit 4.4, TestNG 5.5等等。 TestContext框架也強調(diào)了約定優(yōu)于配置的重要性,它提供了合理的默認值,同時也可以通過基于注解的配置進行改寫。

除了一般的測試基礎(chǔ)設(shè)施外,TestContext框架還以抽象支持類的形式對JUnit 3.8、JUnit 4.4和TestNG 5.5提供了顯式的支持。 針對JUnit 4.4,該框架還提供了一個自定義的Runner,這使得用戶無需繼承特定的類就可以編寫測試類了。

以下章節(jié)給出了TestContext框架的內(nèi)部概覽。 如果你僅僅關(guān)注如何使用該框架而不是使用你自己的監(jiān)聽器去擴展它,那么請直接跳到配置(上下文管理和緩存、 依賴注入、事務(wù)管理)、 支持類及注解支持章節(jié)。

8.3.7.1.?主要的抽象

框架的核心包括TestContextTestContextManager類以及TestExecutionListener接口。 每次測試都會創(chuàng)建TestContextManager。TestContextManager管理了一個TestContext, 它負責(zé)持有當(dāng)前測試的上下文。TestContextManager還負責(zé)在測試執(zhí)行過程中更新TestContext的狀態(tài)并代理到TestExecutionListener, 它用來監(jiān)測測試實際的執(zhí)行(如提供依賴注入、管理事務(wù)等等)。請查看JavaDoc及Spring測試套件以獲得進一步的信息和各種配置示例。

  • TestContext:封裝測試執(zhí)行的上下文,與當(dāng)前使用的測試框架無關(guān)。

  • TestContextManagerSpring TestContext Framework的主入口點, 負責(zé)管理單獨的TestContext并在定義好的執(zhí)行點上向所有注冊的TestExecutionListener發(fā)出事件通知: 測試實例的準備,先于特定的測試框架的前置方法,遲于后置方法。

  • TestExecutionListener:定義了一個監(jiān)聽器API與TestContextManager發(fā)布的測試執(zhí)行事件進行交互, 而該監(jiān)聽器就是注冊到這個TestContextManager上的。

    Spring提供了TestExecutionListener的三個實現(xiàn), 他們都是使用默認值進行配置的(通過@TestExecutionListeners注解): DependencyInjectionTestExecutionListener、DirtiesContextTestExecutionListenerTransactionalTestExecutionListener, 他們對測試實例提供了依賴注入支持,處理@DirtiesContext注解,并分別使用默認的回滾語義對測試提供事務(wù)支持。

以下三個章節(jié)講述了如何通過注解配置TestContext框架并提供了使用該框架編寫真實的單元和集成測試的示例。

8.3.7.2.?上下文管理和緩存

每個TestContext都會為其所負責(zé)的測試實例提供上下文和緩存管理。 測試實例不會自動訪問配置好的ApplicationContext;然而,如果一個測試類實現(xiàn)了ApplicationContextAware接口, 那么測試實例就會擁有一個對ApplicationContext的引用(假如默認已經(jīng)配置好了DependencyInjectionTestExecutionListener)。 AbstractJUnit38SpringContextTestsAbstractJUnit4SpringContextTestsAbstractTestNGSpringContextTests已經(jīng)實現(xiàn)了ApplicationContextAware, 因此自帶了上述功能。

與JUnit 3.8遺留支持不同,使用TestContext框架的測試類無需重寫任何protected成員方法來配置應(yīng)用上下文。 只需在類層次上聲明@ContextConfiguration注解就可以完成配置。 如果你的測試類沒有顯式聲明任何應(yīng)用上下文資源的位置,那么配置好的ContextLoader就會決定如何以及是否從默認的集合位置上加載一個上下文。 例如,GenericXmlContextLoader - 默認的ContextLoader - 會基于測試類的名字產(chǎn)生一個默認的位置。 如果類名叫做com.example.MyTest,那么GenericXmlContextLoader就會從"classpath:/com/example/MyTest-context.xml"加載應(yīng)用上下文。

package com.example;

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/com/example/MyTest-context.xml"
@ContextConfiguration
public class MyTest {
    // class body...
}

如果默認位置不適合你的需求,你可以使用一個包含了XML配置元數(shù)據(jù)的資源位置的數(shù)組來配置@ContextConfigurationlocations屬性 (假如已經(jīng)配置好了一個可以使用XML的ContextLoader)- 一般在classpath上,該屬性被用來配置應(yīng)用程序。 這就和在web.xml或者其他部署配置中指定配置列表時,方法完全一樣,或者幾乎一樣。 作為另外一種選擇,你可以實現(xiàn)并配置自己的ContextLoader

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml" and "/applicationContext-test.xml"
// in the root of the classpath
@ContextConfiguration(locations={"/applicationContext.xml", "/applicationContext-test.xml"})
public class MyTest {
    // class body...
}

@ContextConfiguration還提供了一個boolean類型的inheritLocations屬性以表明是否繼承父類的locations。 其默認值是true,表明一個被注解的類會繼承被注解的父類中定義的資源位置。 特別地,一個被注解的類的資源位置會附加到其被注解的父類中的資源位置列表上。這樣子類就可以繼承資源位置列表。 在下面的例子中,將按順序從"/base-context.xml""/extended-context.xml"中加載針對ExtendedTestApplicationContext。 所以定義在"/extended-context.xml"中的Beans會覆蓋掉定義在"/base-context.xml"中的Beans。

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/base-context.xml" in the root of the classpath
@ContextConfiguration(locations={"/base-context.xml"})
public class BaseTest {
    // class body...
}

// ApplicationContext will be loaded from "/base-context.xml" and "/extended-context.xml"
// in the root of the classpath
@ContextConfiguration(locations={"/extended-context.xml"})
public class ExtendedTest extends BaseTest {
    // class body...
}

如果將inheritLocations設(shè)為false,那么就會屏蔽掉父類的資源位置,然后可以替換父類中定義的任何資源位置。

默認情況下, 配置好的ApplicationContext一旦被加載就會重用到每個測試上。這樣設(shè)置的成本僅產(chǎn)生一次(每個測試fixture), 隨后測試的執(zhí)行就會很快了。在某些不太可能發(fā)生的情況下,一個測試可能會破壞應(yīng)用上下文, 這時它需要重新加載 - 例如,通過改變應(yīng)用對象的bean定義或者狀態(tài) - 你可以使用@DirtiesContext (假設(shè)默認已經(jīng)配置了DirtiesContextTestExecutionListener)來注解測試方法使得測試fixture重新加載配置文件并在測試下次執(zhí)行前重新構(gòu)建應(yīng)用上下文。

8.3.7.3.?測試fixture的依賴注入

當(dāng)你配置DependencyInjectionTestExecutionListener時 - 它會被默認配置 - 通過@TestExecutionListeners注解, 你的測試實例依賴的bean會被注入,而這些bean是通過@ContextConfiguration使用Setter注入、Field注入或者兩者都有來注入的, 到底使用哪種方式取決于你選擇的注解以及你將它們放到setter方法中還是屬性中。為了與Spring 2.5的注解保持一致, 你可以選擇Spring的@Autowired注解或者JSR 250中的@Resource注解。其語義對于Spring框架來說都是一致的。 例如, 如果你喜歡 按類型自動織入, 那么請使用@Autowired來注解你的settter方法或者屬性。另一方面,如果你喜歡按名字注入, 那么請使用@Resource來注解你的settter方法或者屬性。

提示

TestContext框架沒有監(jiān)測測試實例的實例化方式。所以對構(gòu)造方法使用@Autowired將毫無意義。

既然@Autowired執(zhí)行按類型自動編織, 那么如果你有相同類型的多個bean定義的話,對那些特定的bean就不能使用該方式。在這種情況下, 你可以使用@Resource按名字注入。另外,如果你的測試類實現(xiàn)了ApplicationContextAware, 就可以直接訪問ApplicationContext并調(diào)用applicationContext.getBean("titleDao")執(zhí)行一個顯式的查找。

如果你不想讓你的測試實例使用依賴注入,只要不將@Autowired或者@Resource注解到任何屬性或者setter方法上就行了。 另一種方式,你可以使用@TestExecutionListeners并忽略掉監(jiān)聽器列表中的DependencyInjectionTestExecutionListener.class就可以完全禁用依賴注入。

考慮如下場景:我們有一個類,名字叫HibernateTitleDao(通用目標章節(jié)已經(jīng)進行了介紹)。 首先,讓我們看看基于JUnit 4.4的測試類的實現(xiàn),它使用@Autowired進行屬性注入(在所有示例代碼之后我們會查看應(yīng)用上下文的配置)。 注意:下面代碼的依賴注入行為并不是特定于JUnit 4.4的。同樣的依賴注入技術(shù)可以使用在任何測試框架中。

@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration(locations={"daos.xml"})
public final class HibernateTitleDaoTests {

    // this instance will be dependency injected by type
    @Autowired    
    private HibernateTitleDao titleDao;

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }
}

此外,我們可以使用@Autowired進行setter注入。

@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration(locations={"daos.xml"})
public final class HibernateTitleDaoTests {

    // this instance will be dependency injected by type
    private HibernateTitleDao titleDao;

    @Autowired
    public void setTitleDao(HibernateTitleDao titleDao) {
        this.titleDao = titleDao;
    }

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }
}

現(xiàn)在讓我們看看使用@Resource進行屬性注入的一個示例。

@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration(locations={"daos.xml"})
public final class HibernateTitleDaoTests {

    // this instance will be dependency injected by name
    @Resource
    private HibernateTitleDao titleDao;

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }
}

最后,這是使用@Resource進行setter注入的一個示例。

@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration(locations={"daos.xml"})
public final class HibernateTitleDaoTests {

    // this instance will be dependency injected by name
    private HibernateTitleDao titleDao;
    
    @Resource
    public void setTitleDao(HibernateTitleDao titleDao) {
        this.titleDao = titleDao;
    }

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }
}

上面的代碼使用了相同的XML上下文文件,@ContextConfiguration注解使用了這些信息(如 "daos.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">

    <!-- this bean will be injected into the HibernateTitleDaoTests class -->
    <bean id="titleDao" class="com.foo.dao.hibernate.HibernateTitleDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <!-- dependencies elided for clarity -->
    </bean>

</beans>

8.3.7.4.?事務(wù)管理

在TestContext框架中,事務(wù)是由TransactionalTestExecutionListener進行管理的, 默認情況下這是通過@TestExecutionListeners注解進行配置的, 即使你沒有在測試類中顯式聲明 @TestExecutionListeners注解。 為了支持事務(wù),你必須通過@ContextConfiguration在應(yīng)用上下文中加載一個PlatformTransactionManager bean。 此外,你必須在類或方法層次上聲明一個@Transactional

請參考TestContext框架的注解支持中的@TransactionConfiguration以了解類層次的事務(wù)配置(例如為事務(wù)管理器設(shè)置bean名稱以及默認的回滾標志)。

為每個測試方法配置事務(wù)時有幾種選項。如果對于整個類來說事務(wù)不可用,那么可以使用@Transactional來顯式注解方法。 與此類似,如果對于整個類來說事務(wù)可用,那么可以使用@NotTransactional來注解方法表明不為該方法增加事務(wù)。 你可以使用@Rollback注解覆蓋類級別的默認的回滾設(shè)置進而針對一個特定的測試方法控制其事務(wù)的提交。

請注意,AbstractTransactionalJUnit38SpringContextTestsAbstractTransactionalJUnit4SpringContextTestsAbstractTransactionalTestNGSpringContextTests已經(jīng)在類級別預(yù)先配置好了事務(wù)支持。

偶爾你需要在一個事務(wù)性測試方法前、后執(zhí)行某些代碼,而這些代碼是處在事務(wù)上下文之外的,例如, 在測試執(zhí)行前去驗證初始的數(shù)據(jù)庫狀態(tài)或者在測試執(zhí)行后驗證期待的事務(wù)提交行為(舉例來說,該測試被配置為不進行回滾的)。 支持@BeforeTransaction@AfterTransaction注解的TransactionalTestExecutionListener正好適用于這種情況。 使用這些注解之一來注解測試類中任何的public void方法, 同時TransactionalTestExecutionListener會保證你的事務(wù)方法之前的代碼或者事務(wù)方法之后的代碼會在正確的時間執(zhí)行。

提示

任意前置方法 (如使用JUnit 4的@Before所注解的方法)和后置方法 (如使用JUnit 4的@After所注解的方法)都會一個事務(wù)中得到執(zhí)行。 此外,使用 @NotTransactional注解的測試不會執(zhí)行@BeforeTransaction@AfterTransaction所注解的方法。

下面的基于JUnit 4的示例展示了一個假想的集成測試場景,重點闡述了事務(wù)相關(guān)的注解。請查看參考手冊的TestContext框架注解支持章節(jié)以了解進一步的信息和配置示例。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
@Transactional
public class FictitiousTransactionalTest {

	@BeforeTransaction
	public void verifyInitialDatabaseState() {
		// logic to verify the initial state before a transaction is started
	}

	@Before
	public void setUpTestDataWithinTransaction() {
		// set up test data within the transaction
	}

	@Test
	// overrides the class-level defaultRollback setting
	@Rollback(true)
	public void modifyDatabaseWithinTransaction() {
		// logic which uses the test data and modifies database state
	}

	@After
	public void tearDownWithinTransaction() {
		// execute "tear down" logic within the transaction
	}

	@AfterTransaction
	public void verifyFinalDatabaseState() {
		// logic to verify the final state after transaction has rolled back
	}

	@Test
	@NotTransactional
	public void performNonDatabaseRelatedAction() {
		// logic which does not modify database state
	}
}

8.3.7.5.?TestContext支持類

8.3.7.5.1.?JUnit 3.8支持類

org.springframework.test.context.junit38包為基于JUnit 3.8的測試用例提供了支持類。

  • AbstractJUnit38SpringContextTests

    對集成了Spring TestContext Framework與JUnit 3.8環(huán)境中的ApplicationContext測試支持的TestCase進行了抽象。 當(dāng)你繼承AbstractJUnit38SpringContextTests類時,你就可以訪問到protected的成員變量:

    • applicationContext:使用它進行顯式的bean查找或者測試整個上下文的狀態(tài)。

  • AbstractTransactionalJUnit38SpringContextTests

    對為JDBC訪問增加便捷功能的AbstractJUnit38SpringContextTests事務(wù)擴展進行抽象。 需要在ApplicationContext中定義一個javax.sql.DataSource bean和一個PlatformTransactionManager bean。 當(dāng)你繼承AbstractTransactionalJUnit38SpringContextTests類時,你就可以訪問到protected的成員變量:

    • applicationContext:從AbstractJUnit38SpringContextTests父類繼承。使用它執(zhí)行bean的查找或者測試整個上下文的狀態(tài)

    • simpleJdbcTemplate:在查詢以確認狀態(tài)時非常有用。例如,應(yīng)用代碼要創(chuàng)建一個對象,然后使用ORM工具將其持久化, 這時你想在測試代碼執(zhí)行前后對其進行查詢,以確定數(shù)據(jù)是否插入到數(shù)據(jù)庫中(Spring會保證該查詢運行在相同事務(wù)內(nèi))。 你需要告訴你的ORM工具‘flush’其改變以正確完成任務(wù),例如,使用HibernateSession接口的flush()方法。

8.3.7.5.2.?JUnit 4.4支持類

org.springframework.test.context.junit4包為基于JUnit 4.4的測試用例提供了支持類。

  • AbstractJUnit4SpringContextTests

    對集成了Spring TestContext Framework與JUnit 4.4環(huán)境中的ApplicationContext測試支持的基本測試類進行了抽取。

    當(dāng)你繼承AbstractJUnit4SpringContextTests時,你就可以訪問到protected的成員變量:

    • applicationContext:使用它進行顯式的bean查找或者測試整個上下文的狀態(tài)。

  • AbstractTransactionalJUnit4SpringContextTests

    對為JDBC訪問增加便捷功能的AbstractJUnit4SpringContextTests事務(wù)擴展進行抽象。 需要在ApplicationContext中定義一個javax.sql.DataSource bean和一個PlatformTransactionManager bean。

    當(dāng)你繼承AbstractTransactionalJUnit4SpringContextTests類時,你就可以訪問到下列protected的成員變量:

    • applicationContext:繼承自父類AbstractJUnit4SpringContextTests。 使用它執(zhí)行bean的查找或者測試整個上下文的狀態(tài)

    • simpleJdbcTemplate:當(dāng)通過查詢來確認狀態(tài)時非常有用。例如,應(yīng)用代碼要創(chuàng)建一個對象, 然后使用ORM工具將其持久化,這時你想在測試代碼執(zhí)行前后對其進行查詢,以確定數(shù)據(jù)是否插入到數(shù)據(jù)庫中。 (Spring會保證該查詢運行在相同事務(wù)內(nèi)。)你需要告訴你的ORM工具‘flush’其改變以正確完成任務(wù),例如, 使用HibernateSession接口的flush()方法。

提示

這些類僅僅為擴展提供了方便。 如果你不想將你的測試類綁定到Spring的類上 - 例如,如果你要直接擴展你想測試的類 - 只需要通過@RunWith(SpringJUnit4ClassRunner.class)、 @ContextConfiguration@TestExecutionListeners等注解來配置你自己的測試類就可以了。

8.3.7.5.3.?定制JUnit 4.4運行器

Spring TestContext Framework通過一個可定制的運行器提供了與JUnit 4.4的完全集成。 通過使用@Runwith(SpringJUnit4ClassRunner.class)來注解測試類,開發(fā)者可以實現(xiàn)標準的JUnit 4.4單元和集成測試, 同時還能獲得TestContext框架的好處,如對加載應(yīng)用上下文的支持,測試實例的依賴注入,執(zhí)行事務(wù)性測試方法等等。 下面的代碼清單顯示了使用定制的Spring Runner來配置一個測試類的最小需求。 注意,我們使用一個空的列表來配置@TestExecutionListeners以便禁用默認的監(jiān)聽器, 否則需要通過@ContextConfiguration配置一個 ApplicationContext

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public class SimpleTest {

	@Test
	public void testMethod() {
		// execute test logic...
	}
}
8.3.7.5.4.?TestNG支持類

org.springframework.test.context.testng包為基于TestNG的測試用例提供了支持類。

  • AbstractTestNGSpringContextTests

    對集成了Spring TestContext Framework與TestNG環(huán)境中的ApplicationContext測試支持的基礎(chǔ)測試類進行了抽象。

    當(dāng)你繼承AbstractTestNGSpringContextTests時,就可以訪問到下列protected的成員變量:

    • applicationContext:使用它進行顯式的bean查找或者測試整個上下文的狀態(tài)。

  • AbstractTransactionalTestNGSpringContextTests

    對為JDBC訪問增加便捷功能的AbstractTestNGSpringContextTests事務(wù)擴展進行抽象。 需要在ApplicationContext中定義一個javax.sql.DataSource bean和一個PlatformTransactionManager bean。

    當(dāng)你繼承AbstractTransactionalTestNGSpringContextTests類時,就可以訪問下列protected的成員變量:

    • applicationContext:繼承自父類AbstractTestNGSpringContextTests。使用它執(zhí)行bean的查找或者測試整個上下文的狀態(tài)。

    • simpleJdbcTemplate:當(dāng)通過查詢來確認狀態(tài)時非常有用。例如,應(yīng)用代碼要創(chuàng)建一個對象, 然后使用ORM工具將其持久化,這時你想在測試代碼執(zhí)行前后對其進行查詢,以確定數(shù)據(jù)是否插入到數(shù)據(jù)庫中。(Spring會保證該查詢運行在相同事務(wù)內(nèi)。) 你需要告訴你的ORM工具‘flush’其改變以正確完成任務(wù),例如,使用HibernateSession接口的flush()方法。

提示

這些類僅僅為擴展提供了方便。 如果你不想將你的測試類綁定到Spring的類上 - 例如,如果你要直接擴展你想測試的類 - 只需要通過 @ContextConfiguration、@TestExecutionListeners等注解來配置你自己的測試類就可以了。 并使用TestContextManager來手工監(jiān)測你的測試類。 請查看AbstractTestNGSpringContextTests的源代碼以了解如何檢測你自己的測試類。

8.3.7.6.?TestContext框架注解支持

Spring TestContext Framework支持通用注解章節(jié)提到的所有注解。 然而下面的這些注解只有配合JUnit才能使用(比如搭配SpringJUnit4ClassRunner或者 JUnit 3.8及JUnit 4.4支持類)。

  • @IfProfileValue

  • @ProfileValueSourceConfiguration

  • @ExpectedException

    協(xié)同使用Spring的@ExpectedException注解與JUnit 4的@Test(expected=...)會導(dǎo)致一個不可避免的沖突。 因此當(dāng)與JUnit 4集成時,開發(fā)者必須選擇其中一個,在這種情況下建議使用顯式的JUnit 4配置。

  • @Timed

    Spring的@Timed注解與JUnit 4的@Test(timeout=...)支持具有不同的語義。 特別地,鑒于JUnit 4處理測試執(zhí)行超時(如通過在一個單獨的線程中執(zhí)行測試方法)的方式, 我們不可能在一個事務(wù)上下文中的測試方法上使用JUnit的@Test(timeout=...)配置。因此, 如果你想將一個測試方法配置成計時具事務(wù)性的, 你就必須聯(lián)合使用Spring的@Timed@Transactional注解。 還值得注意的是@Test(timeout=...)只管測試方法本身執(zhí)行的次數(shù),如果超出的話立刻就會失??; 然而,@Timed關(guān)注的是測試執(zhí)行的總時間(包括建立和銷毀操作以及重復(fù)),并且不會令測試失敗。

  • @Repeat

Spring TestContext Framework還支持下面這些非特定于測試的注解,并且保持其語義不變。

  • @Autowired

  • @Qualifier

  • @Resource (javax.annotation)如果JSR-250可用

  • @PersistenceContext (javax.persistence)如果JPA可用

  • @PersistenceUnit (javax.persistence)如果JPA可用

  • @Required

  • @Transactional

下面的列表包含了特定于Spring TestContext Framework的所有注解。請查看相應(yīng)的JavaDoc以了解進一步的信息,包括默認的屬性值等等。

  • @ContextConfiguration

    定義類級別的元數(shù)據(jù)以決定如何加載和配置ApplicationContext。特別地, @ContextConfiguration定義了要加載的應(yīng)用上下文資源位置以及用來加載上下文的ContextLoader策略。

    @ContextConfiguration(locations={"example/test-context.xml"}, loader=CustomContextLoader.class)
    public class CustomConfiguredApplicationContextTests {
        // class body...
    }

    注意:@ContextConfiguration默認情況下為繼承的資源位置提供了支持。 查看上下文管理和緩存章節(jié)及JavaDoc來了解更多的示例和細節(jié)信息。

  • @TestExecutionListeners

    定義類級別的元數(shù)據(jù),TestExecutionListeners會使用TestContextManager進行注冊。 通常,@TestExecutionListeners@ContextConfiguration會搭配使用。

    @ContextConfiguration
    @TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class})
    public class CustomTestExecutionListenerTests {
        // class body...
    }

    注意:@TestExecutionListeners默認情況下為繼承的監(jiān)聽器提供了支持。查看JavaDoc來了解更多的示例和細節(jié)信息。

  • @TransactionConfiguration

    為配置事務(wù)性測試定義了類級別的元數(shù)據(jù)。特別地,如果需要的PlatformTransactionManager不是“transactionManager”的話, 那么可以顯式配置驅(qū)動事務(wù)的PlatformTransactionManager的bean名字。此外, 可以將defaultRollback標志改為false。通常, @TransactionConfiguration@ContextConfiguration搭配使用。

    @ContextConfiguration
    @TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
    public class CustomConfiguredTransactionalTests {
        // class body...
    }
  • @BeforeTransaction

    表明被注解的public void方法應(yīng)該在測試方法的事務(wù)開始之前執(zhí)行, 該事務(wù)是通過@Transactional注解來配置的。

    @BeforeTransaction
    public void beforeTransaction() {
        // logic to be executed before a transaction is started
    }
  • @AfterTransaction

    表明被注解的public void方法應(yīng)該在測試方法的事務(wù)結(jié)束之后執(zhí)行, 該事務(wù)是通過@Transactional注解來配置的。

    @AfterTransaction
    public void afterTransaction() {
        // logic to be executed after a transaction has ended
    }

8.3.8.?PetClinic示例

在Spring的完整發(fā)行包里包含了PetClinic示例應(yīng)用,它以JUnit 4.4環(huán)境闡述了Spring TestContext Framework的幾個特性。 大多數(shù)功能包含在AbstractClinicTests里,部分內(nèi)容列舉如下:

@ContextConfiguration
public abstract class AbstractClinicTests extends AbstractTransactionalJUnit4SpringContextTests {

	@Autowired
	protected Clinic clinic;

	@Test
	public void getVets() {
		Collection<Vet> vets = this.clinic.getVets();
		assertEquals("JDBC query must show the same number of vets",
			super.countRowsInTable("VETS"), vets.size());
		Vet v1 = EntityUtils.getById(vets, Vet.class, 2);
		assertEquals("Leary", v1.getLastName());
		assertEquals(1, v1.getNrOfSpecialties());
		assertEquals("radiology", (v1.getSpecialties().get(0)).getName());
		// ...
	}
	
	// ...
}

注意:

  • 該測試用例繼承了AbstractTransactionalJUnit4SpringContextTests類, 從這里它繼承了針對依賴注入的配置(通過DependencyInjectionTestExecutionListener)和事務(wù)性行為(通過TransactionalTestExecutionListener)。

  • clinic成員變量 - 要測試的應(yīng)用程序?qū)ο?- 是通過@Autowired進行依賴注入的。

  • testGetVets()方法說明如何使用繼承下來的countRowsInTable()方法來輕松驗證表中的行數(shù), 進而測試應(yīng)用代碼的正確行為。這點允許實現(xiàn)更強大的測試,減少了對確切測試數(shù)據(jù)的依賴。例如,無需打斷測試就可以向數(shù)據(jù)庫中增加新行。

  • 像很多使用數(shù)據(jù)庫的集成測試一樣,AbstractClinicTests中的大多數(shù)測試依賴于測試運行前數(shù)據(jù)庫中已有的最小量的數(shù)據(jù)。 但是你可能在測試用例中改變數(shù)據(jù)庫――當(dāng)然,在同一個事務(wù)中。

PetClinic應(yīng)用支持三種數(shù)據(jù)訪問技術(shù) - JDBC、Hibernate及JPA。無需任何特定的資源位置, 只要聲明了@ContextConfiguration,那么AbstractClinicTests類就會從默認位置加載其應(yīng)用上下文, 該默認位置為"AbstractClinicTests-context.xml",這里聲明了一個通用的DataSource。 子類指定了額外的上下文位置,這就要求它必須聲明一個PlatformTransactionManagerClinic的一個具體實現(xiàn)。

例如,PetClinic測試的Hibernate實現(xiàn)包含以下實現(xiàn)。針對這個例子請注意,HibernateClinicTests沒有包含一行代碼: 我們只需聲明@ContextConfiguration并且測試繼承于AbstractClinicTests。 既然無需任何特定的資源位置就可以聲明@ContextConfiguration, 那么Spring TestContext Framework就會從"AbstractClinicTests-context.xml" (例如繼承的位置)和 "HibernateClinicTests-context.xml"中加載應(yīng)用上下文, 同時"HibernateClinicTests-context.xml" 中定義的bean會覆蓋掉"AbstractClinicTests-context.xml"中定義的bean。

@ContextConfiguration
public class HibernateClinicTests extends AbstractClinicTests { }

正如你在PetClinic應(yīng)用中所看到的,Spring配置文件被劃分成多個文件。對于大型應(yīng)用來說都是這樣做的, 配置位置通常被指定在一個針對該應(yīng)用程序集成測試的通用基類中。 這樣的基類還可以增加有用的實例變量 - 很自然地由依賴注入組裝 - 例如使用Hibernate的應(yīng)用中的HibernateTemplate。

從長遠來看,集成測試中的Spring配置文件應(yīng)該與部署環(huán)境中的一樣。一個可能的不同點是數(shù)據(jù)庫連接池和事務(wù)基礎(chǔ)設(shè)施。 如果你正部署到一個完整的應(yīng)用服務(wù)器上,那你可能會使用其連接池(通過JNDI訪問)和JTA實現(xiàn)。 這樣依賴,在生產(chǎn)階段你會使用JndiObjectFactoryBean來獲得DataSourceJtaTransactionManager。 在容器外的集成測試中無法使用JNDI和JTA,因此你應(yīng)該為他們使用一個替代的組合, 如Commons DBCP BasicDataSourceDataSourceTransactionManager或者HibernateTransactionManager。 你可以將這種不同的行為放到一個單獨的XML文件中,在應(yīng)用服務(wù)器和獨立于其他配置的'本地'配置中自由選擇,這不會在測試和產(chǎn)品環(huán)境中造成差異。 此外,建議使用屬性文件來存放連接信息:請查看PetClinic應(yīng)用以了解這些。

上一篇: 下一篇: