`
langgufu
  • 浏览: 2306988 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring TestContext测试框架

阅读更多

直接使用Junit测试Spring程序存在的不足... 1

Spring TestContext 测试框架体系结构... 2

TestContext 核心类、支持类以及注解类... 2

TestContext. 2

TestContextManager. 2

TestExecutionListener. 2

@TestExecutionListeners. 3

@ContextConfiguration. 3

@RunWith. 3

SpringJUnit4ClassRunner. 3

ContextCache. 4

ContextLoader. 4

ApplicationContextAware. 4

AbstractJUnit4SpringContextTests. 4

AbstractTransactionalJUnit4SpringContextTests. 5

常用注解... 5

@IfProfileValue. 5

@ProfileValueSourceConfiguration. 5

@DirtiesContext. 6

@ExpectedException. 6

@Timed. 6

@Repeat. 7

@Rollback. 7

@Transactional7

@NotTransactional7

@Autowired. 8

@Resource. 8

@Qualifier. 9

@TransactionConfiguration. 9

@BeforeTransaction. 9

@AfterTransaction. 9

总结... 10

 

基于注解的TestContext测试框架,它采用注解技术可以让POJO成为Spring的测试用例,可以运行在Junit3.8 Junit4.4 TestNG等测试框架之下

直接使用Junit测试Spring程序存在的不足

1.       导致Spring容器多次初始化问题:

根据 JUnit 测试用例的调用流程,每执行一个测试方法都会重新创建一个测试用例实例并调用其 setUp() 方法。由于在一般情况下,我们都在 setUp() 方法中初始化 Spring 容器,这意味着测试用例中有多少个测试方法,Spring 容器就会被重复初始化多少次。

2.       需要使用硬编码方式手工获取Bean

在测试用例中,我们需要通过 ApplicationContext.getBean() 的方法从 Spirng 容器中获取需要测试的目标 Bean,并且还要进行造型操作。

3.       数据库现场容易遭受破坏

测试方法可能会对数据库记录进行更改操作,破坏数据库现场。虽然是针对开发数据库进行测试工作的,但如果数据操作的影响是持久的,将会形成积累效应并影响到测试用例的再次执行。举个例子,假设在某个测试方法中往数据库插入一条 ID 1 t_user 记录,第一次运行不会有问题,第二次运行时,就会因为主键冲突而导致测试用例执行失败。所以测试用例应该既能够完成测试固件业务功能正确性的检查,又能够容易地在测试完成后恢复现场,做到踏雪无迹、雁过无痕。

4.       不容易在同一事务下访问数据库以检验业务操作的正确性

当测试固件操作数据库时,为了检测数据操作的正确性,需要通过一种方便途径在测试方法相同的事务环境下访问数据库,以检查测试固件数据操作的执行效果。如果直接使用 JUnit 进行测试,我们很难完成这项操作。

 

Spring 测试框架是专门为测试基于 Spring 框架应用程序而设计的,它能够让测试用例非常方便地和 Spring 框架结合起来,以上所有问题都将迎刃而解。

 

 

Spring TestContext 测试框架体系结构

TestContext 核心类、支持类以及注解类

TestContext 测试框架的核心由 org.springframework.test.context 包中三个类组成,分别是 TestContext TestContextManager 类以及 TestExecutionListener 接口。

 

每次测试都会创建TestContextManagerTestContextManager管理了一个TestContext它负责持有当前测试的上下文。TestContextManager还负责在测试执行过程中更新TestContext的状态并代理到TestExecutionListener它用来监测测试实际的执行(如提供依赖注入、管理事务等等)

TestContext

TestContext:封装测试执行的上下文,与当前使用的测试框架无关。

TestContextManager

TestContextManagerSpring TestContext Framework的主入口点,负责管理单独的TestContext并在定义好的执行点上向所有注册的TestExecutionListener发出事件通知:测试实例的准备,先于特定的测试框架的前置方法,迟于后置方法

 

TestExecutionListener

TestExecutionListener:定义了一个监听器API与TestContextManager发布的测试执行事件进行交互,而该监听器就是注册到这个TestContextManager上的。

Spring提供了TestExecutionListener的三个实现, 他们都是使用默认值进行配置的(通过@TestExecutionListeners注解): DependencyInjectionTestExecutionListenerDirtiesContextTestExecutionListenerTransactionalTestExecutionListener,他们对测试实例提供了依赖注入支持,处理@DirtiesContext注解,并分别使用默认的回滚语义对测试提供事务支持。

 

 

 

DependencyInjectionTestExecutionListener:该监听器提供了自动注入的功能,它负责解析测试用例中 @Autowried 注解并完成自动注入;

DirtiesContextTestExecutionListener:一般情况下测试方法并不会对 Spring 容器上下文造成破坏(改变 Bean 的配置信息等),如果某个测试方法确实会破坏 Spring 容器上下文,你可以显式地为该测试方法添加 @DirtiesContext 注解,以便 Spring TestContext 在测试该方法后刷新 Spring 容器的上下文,而 DirtiesContextTestExecutionListener 监听器的工作就是解析 @DirtiesContext 注解;

TransactionalTestExecutionListener:它负责解析 @Transaction@NotTransactional 以及 @Rollback 等事务注解的注解。@Transaction 注解让测试方法工作于事务环境中,不过在测试方法返回前事务会被回滚。你可以使用 @Rollback(false) 让测试方法返回前提交事务。而 @NotTransactional 注解则让测试方法不工作于事务环境中。此外,你还可以使用类或方法级别的 @TransactionConfiguration 注解改变事务管理策略

 

@TestExecutionListeners

用来注册TestExecutionListener

@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})

 

@ContextConfiguration

用来指定加载的Spring配置文件的位置,会加载默认配置文件

1.     locations属性

@ContextConfiguration不带locations属性,GenericXmlContextLoader会基于测试类的名字产生一个默认的位置.

如果类名叫做com.example.MyTest,那么GenericXmlContextLoader就会从"classpath:/com/example/MyTest-context.xml"加载应用上下文。

@ContextConfiguration 若带有locations属性

@ContextConfiguration(locations= { "spring-service.xml","spring-service1.xml" })  会去加载指定文件

 

2.       inheritLocations属性

@ContextConfigurationinheritLocations属性 (是否继承父类的locations),默认为true

@ContextConfiguration(locations={"/base-context.xml"})

@ContextConfiguration(locations={"/extended-context.xml"})

true,会将/base-context.xml, /extended-context.xml 合并加载,若有重载的bean为子类为准

false,屏蔽掉父类的资源位置

 

@RunWith

@RunWith 注解指定测试用例的运行器

@RunWith(SpringJUnit4ClassRunner.class)

SpringJUnit4ClassRunner

Spring TestContext 框架提供了扩展于 org.junit.internal.runners.JUnit4ClassRunner SpringJUnit4ClassRunner 运行器,它负责总装 Spring TestContext 测试框架并将其统一到 JUnit 4.4 框架中。

 

它负责无缝地将 TestContext 测试框架移花接木到 JUnit 4.4 测试框架中,它是 Spring TestContext 可以运行起来的根本所在

 

持有TestContextManager的引用

privatefinal TestContextManager testContextManager;

 

ContextCache

缓存ApplicationContext

 

 

ContextLoader

Interface  加载context接口

 

 

GenericXmlContextLoader为默认的ContextLoader

ApplicationContextAware

自动加载ApplicationContext

AbstractJUnit4SpringContextTests

对集成了Spring TestContext Framework与JUnit 4.4环境中的ApplicationContext测试支持的基本测试类进行了抽取。

当你继承AbstractJUnit4SpringContextTests时,你就可以访问到protected的成员变量:

o    applicationContext:使用它进行显式的bean查找或者测试整个上下文的状态。

 

AbstractTransactionalJUnit4SpringContextTests

对为JDBC访问增加便捷功能的AbstractJUnit4SpringContextTests事务扩展进行抽象。 需要在ApplicationContext中定义一个javax.sql.DataSource bean和一个PlatformTransactionManager bean。

当你继承AbstractTransactionalJUnit4SpringContextTests类时,你就可以访问到下列protected的成员变量:

o    applicationContext:继承自父类AbstractJUnit4SpringContextTests。 使用它执行bean的查找或者测试整个上下文的状态

o    simpleJdbcTemplate:当通过查询来确认状态时非常有用。例如,应用代码要创建一个对象,然后使用ORM工具将其持久化,这时你想在测试代码执行前后对其进行查询,以确定数据是否插入到数据库中。 (Spring会保证该查询运行在相同事务内。)你需要告诉你的ORM工具‘flush’其改变以正确完成任务,例如,使用HibernateSession接口的flush()方法。

提示

这些类仅仅为扩展提供了方便。 如果你不想将你的测试类绑定到Spring的类上 - 例如,如果你要直接扩展你想测试的类 - 只需要通过@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration@TestExecutionListeners等注解来配置你自己的测试类就可以了。

常用注解

Spring框架在org.springframework.test.annotation包中提供了常用的Spring特定的注解集,如果你在Java5或以上版本开发,可以在测试中使用它。

 

@IfProfileValue

提示一下,注解测试只针对特定的测试环境。如果配置的ProfileValueSource类返回对应的提供者的名称值这个测试就可以启动。这个注解可以应用到一个类或者单独的方法。

 

@IfProfileValue(name="java.vendor", value="Sun Microsystems Inc.")

publicvoid testJoin() {

    System.out.println(System.getProperty("java.vendor"));

}

 

@ProfileValueSourceConfiguration

类级别注解用来指定当通过@IfProfileValue注解获取已配置的profile时使用何种ProfileValueSource如果@ProfileValueSourceConfiguration没有在测试中声明,将默认使用SystemProfileValueSource

 

@ProfileValueSourceConfiguration(CustomProfileValueSource.class)

 

SystemProfileValueSource中的代码

public String get(String key) {

    Assert.hasText(key, "'key' must not be empty");

    return System.getProperty(key);

}

 

@DirtiesContext

在测试方法上出现这个注解时,表明底层Spring容器在该方法的执行中被“污染”,从而必须在方法执行结束后重新创建(无论该测试是否通过)。

@DirtiesContext

    publicvoid testJoinC() {       

            Assert.assertEquals(true, false);

}

 

@ExpectedException

表明被注解方法预期在执行中抛出一个异常。预期异常的类型在注解中给定。如果该异常的实例在测试方法执行中被抛出,则测试通过。同样的如果该异常实例没有在测试方法执行时抛出,则测试失败。

@ExpectedException(MemberServiceException.class)

publicvoid testChangePassword() {}

协同使用Spring@ExpectedException注解与JUnit 4@Test(expected=...)会导致一个不可避免的冲突。因此当与JUnit 4集成时,开发者必须选择其中一个,在这种情况下建议使用显式的JUnit 4配置。

@Timed

表明被注解的测试方法必须在规定的时间区间内执行完成(以毫秒记)。如果测试执行时间超过了规定的时间区间,测试就失败了。

注意该时间区间包括测试方法本身的执行,任何重复测试(参见 @Repeat),还有任何测试fixtureset uptear down时间。

@Timed(millis=100)

    publicvoid testPersonByVerifiedMobile(){}

 

 

Spring的@Timed注解与JUnit 4的@Test(timeout=...)支持具有不同的语义。 特别地,鉴于JUnit 4处理测试执行超时(如通过在一个单独的线程中执行测试方法)的方式,我们不可能在一个事务上下文中的测试方法上使用JUnit@Test(timeout=...)配置。因此,如果你想将一个测试方法配置成计时具事务性的, 你就必须联合使用Spring@Timed@Transactional注解。 还值得注意的是@Test(timeout=...)只管测试方法本身执行的次数,如果超出的话立刻就会失败;然而,@Timed关注的是测试执行的总时间(包括建立和销毁操作以及重复),并且不会令测试失败。

 

@Repeat

表明被注解的测试方法必须重复执行。执行的次数在注解中声明。

注意重复执行范围包括包括测试方法本身的执行,以及任何测试fixture的set uptear down

@Test

    @Timed(millis=100)

    @Repeat(10)

publicvoid testPersonByVerifiedMobile()

 

@Rollback

表明被注解方法的事务在完成后是否需要被回滚。 如果true,事务将被回滚,否则事务将被提交。 使用@Rollback接口来在类级别覆写配置的默认回滚标志。

@Rollback(false)

publicvoid testPersonByVerifiedMobile()

 

@Transactional

出现该注解表明测试方法必须在事务中执行。

@NotTransactional

出现该注解表明测试方法必须在事务中执行。

@NotTransactional

publicvoid testPersonByVerifiedMobile()

 

 

@Autowired

按类型注入(可以写在属性上也可以写在setter)

@Autowired

Join join11;

 

@Autowired

    publicvoid setJoin11(Join join11) {

        this.join11 = join11;

    }

 

 

@Resource

JSR 250中注解. @Autowired类似

@Resource

    publicvoid setJoin(Join join) {

        this.join = join;

}

 

@Resource

    Join join;

 

@Autowired @Resource 都可以用来装配bean.  都可以写在字段上,或写在set方法上

 

@Autowired (srping提供的默认按类型装配

 

@Resource ( j2ee提供的 ) 默认按名称装配,当找不到(不写name属性)名称匹配的bean再按类型装配.

可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是指定了name属性, 就用 字段名 去做name属性值,一般不用写name属性.

@Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.

 

 

推荐@Autowired @Resource作用有字段就不用写set方法了,也不要写@Resource(name="beanName").

 

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})

public@interfaceAutowired

 

@Qualifier

在需要更多控制的时候,任何autowired的域、构造参数、或者方法参数可以进一步加注@Qualifier注解。qualifier可以包含一个字符串值,在这种情况下,Spring会试图通过名字来找到对应的对象。

@Autowired

    @Qualifier("join")

Join join111;

 

@Qualifier作为一个独立注解存在的主要原因是它可以被应用在构造器参数或方法参数上,但上文提到的@Autowired注解只能运用在构造器或方法本身。

public SpringTest(@Qualifier("join")Join join){

       

    }

看下@Qualifier的定义

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Inherited

@Documented

public@interfaceQualifier

 

 

@TransactionConfiguration

为配置事务性测试定义了类级别的元数据。特别地,如果需要的PlatformTransactionManager不是“transactionManager”的话,那么可以显式配置驱动事务的PlatformTransactionManager的bean名字。此外, 可以将defaultRollback标志改为false。通常, @TransactionConfiguration@ContextConfiguration搭配使用。

@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)

publicclass SpringTest

 

 

@BeforeTransaction

表明被注解的public void方法应该在测试方法的事务开始之前执行,该事务是通过@Transactional注解来配置的。

 

@AfterTransaction

表明被注解的public void方法应该在测试方法的事务结束之后执行,该事务是通过@Transactional注解来配置的。

 

 

标注 @Before @After 注解的方法和测试方法运行在同一个事务中,但有时我们希望在测试方法的事务开始之前或完成之后执行某些方法以便获取数据库现场的一些情况。这时,可以使用 Spring TestContext @BeforeTransaction @AfterTransaction 注解来达到目录(这两个注解位于 org.springframework.test.context.transaction 包中)。

 

 

总结

Spring TestContext 测试框架不但可以整合到 JUnit 4.4 测试框架上,而且还可以整合到 JUnit 3.8 以及 TestNG 等测试框架上。目前已经提供了对 JUnit 3.8 以及 TestNG 的支持,你可以分别在 org.springframework.test.context.junit38 org.springframework.test.context.testng 包下找到整合的帮助类。

 

 

参考资料:

1.       http://www.ibm.com/developerworks/cn/java/j-lo-spring25-test/?S_TACT=105AGX52&S_CMP=techcsdn

2.       Spring-Reference_zh_CN.chm

 

分享到:
评论

相关推荐

    使用 Spring 2.5 TestContext 测试框架

    在本篇文章中,我们将深入探讨Spring 2.5 TestContext测试框架的核心特性和使用方法。 首先,Spring TestContext框架的核心是`@ContextConfiguration`注解,它用于指定测试类中应用上下文的配置。你可以通过此注解...

    spring-test-junit5, JUnit ( a )的spring TestContext框架扩展( a ).zip

    spring-test-junit5, JUnit ( a )的spring TestContext框架扩展( a ) spring 5测试支持这个项目作为 5的正式 Prototype,在 spring TestContext框架测试支持,并与 SPR-13575结合到 Spring Framework 。 因此,在...

    Spring测试框架.rar

    这个压缩包“Spring测试框架.rar”包含了与使用Spring 2.5 TestContext测试框架相关的资源,特别是文档“使用 Spring 2.5 TestContext 测试框架.htm”和其相关的文件夹“使用 Spring 2.5 TestContext 测试框架_files...

    Spring 2.5 TestContext

    Spring 2.5 TestContext框架是Spring框架的一个重要组成部分,主要设计用于简化单元测试和集成测试的编写。这个框架提供了一种结构化的测试环境,它允许开发者在测试中利用Spring的依赖注入特性,以及对...

    Spring TestContext

    Spring TestContext Framework是spring-test模块中提供的一个测试框架,能够用于单元测试和集成测试。

    Spring+hibernate 单元测试

    Spring 2.5 版本引入了一个全新的基于注解的测试框架——TestContext,该框架与之前的测试框架相比有着显著的区别。TestContext 测试框架不再依赖于特定的测试基类,而是采用了更加灵活的注解方式来定义测试行为,这...

    我的笔记 spring的测试

    本笔记将深入探讨Spring框架中的测试支持,包括单元测试、集成测试以及Spring TestContext框架的使用。 首先,我们来看Spring的单元测试。Spring提供了`@RunWith(SpringRunner.class)`注解,它是JUnit的一个扩展,...

    [课堂课件讲解]Java微服务实践-Spring Boot 测试.pptx

    Spring 提供了一个测试框架,名为 Spring TestContext Framework,该框架提供了一个通用的测试环境,可以用于测试 Spring 应用程序。在 Spring 测试中,我们可以使用注解(Annotation)来配置测试环境,例如 @...

    Spring 测试jar

    2. `JUnit`:一个广泛使用的单元测试框架,Spring Test与JUnit深度集成,提供测试注解如`@Test`,`@Before`,`@After`等。 3. `MockitoJUnitRunner`或`SpringRunner`:这两个运行器分别来自Mockito和Spring,帮助...

    通过spring管理的web工程的junit单元测试方法四

    在单元测试中,我们可以利用Spring的TestContext框架来启动一个临时的容器,以便在隔离环境中运行测试。 1. **Spring TestContext框架**: Spring TestContext框架提供了一个统一的入口点,允许我们在JUnit测试中...

    spring测试、struts测试、hibernate测试、软件测试、网站测试、利用JBuilder测试的单元测试技术

    你可以使用JUnit或TestNG作为基础测试框架,结合Spring TestContext Framework来创建和管理测试上下文,以便于隔离和测试单个组件或服务。 接下来,Struts测试主要关注基于Struts框架的应用程序。Struts是一个MVC...

    Spring框架参考文档(中文版PDF)

    对于测试,Spring提供了Mock Objects和TestContext框架,使得单元测试和集成测试变得简单。开发者可以在不依赖外部环境的情况下,轻松创建和运行测试用例。 总的来说,"Spring框架参考文档(中文版PDF)"是一份宝贵...

    Spring5框架课堂笔记.7z

    12. **Spring Test**:提供了全面的单元测试和集成测试支持,包括Mockito、Spring TestContext Framework等工具,确保代码质量。 13. **Spring Security**:Spring的统一安全解决方案,提供身份验证、授权等功能,...

    spring-framework-2.0

    8. **测试支持**:Spring 2.0提供了更好的测试工具和框架,如`Spring TestContext Framework`,可以进行单元测试和集成测试,支持模拟对象和依赖注入到测试类中。 9. **Web Flow**:Spring Web Flow是Spring 2.0...

    Spring 2框架入门

    Spring TestContext Framework进一步增强了测试环境的配置和管理。 8. **AOP代理**:Spring支持JDK动态代理和CGLIB代理,用于实现AOP功能。动态代理用于接口实现类,而CGLIB用于无接口的类。 这份“Wrox.Beginning...

    spring3 junit 测试 + word

    JUnit是Java编程语言中广泛使用的单元测试框架,它使得开发者能够编写易于执行和理解的测试用例,确保代码的质量和稳定性。 在这个“spring3 junit 测试”主题中,我们将深入探讨如何在Spring3环境中集成和使用...

    spring框架DEMO

    DEMO中可能会包含使用Spring TestContext Framework进行测试的例子。 文件名为“www.ahpoll.com”的可能是项目源代码的压缩包,包含了DEMO的所有源码文件。在这些文件中,你可以找到Spring配置文件(如`...

Global site tag (gtag.js) - Google Analytics