- 浏览: 25936 次
- 性别:
- 来自: 泰安
文章分类
最新评论
http://sishuok.com/forum/blogPost/list/0/2557.html
13.3 集成测试
13.3.1 概述
集成测试是在单元测试之上,通常是将一个或多个已进行过单元测试的组件组合起来完成的,即集成测试中一般不会出现Mock对象,都是实实在在的真实实现。
对于单元测试,如前边在进行数据访问层单元测试时,通过Mock HibernateTemplate对象然后将其注入到相应的DAO实现,此时单元测试只测试某层的某个功能是否正确,对其他层如何提供服务采用Mock方式提供。
对于集成测试,如要进行数据访问层集成测试时,需要实实在在的HibernateTemplate对象然后将其注入到相应的DAO实现,此时集成测试将不仅测试该层功能是否正确,还将测试服务提供者提供的服务是否正确执行。
使用Spring的一个好处是能非常简单的进行集成测试,无需依赖web服务器或应用服务器即可完成测试。Spring通过提供一套TestContext框架来简化集成测试,使用TestContext测试框架能获得许多好处,如Spring IoC容器缓存、事务管理、依赖注入、Spring测试支持类等等。
13.3.2 Spring TestContext框架支持
Spring TestContext框架提供了一些通用的集成测试支持,主要提供如下支持:
一、上下文管理及缓存:
对于每一个测试用例(测试类)应该只有一个上下文,而不是每个测试方法都创建新的上下文,这样有助于减少启动容器的开销,提供测试效率。可通过如下方式指定要加载的上下文:
java代码:
查看复制到剪贴板打印
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml"})
public class GoodsHibernateDaoIntegrationTest {
}
locations:指定Spring配置文件位置;
inheritLocations:如果设置为false,将屏蔽掉父类中使用该注解指定的配置文件位置,默认为true表示继承父类中使用该注解指定的配置文件位置。
二、Test Fixture(测试固件)的依赖注入:
Test Fixture可以指运行测试时需要的任何东西,一般通过@Before定义的初始化Fixture方法准备这些资源,而通过@After定义的销毁Fixture方法销毁或还原这些资源。
Test Fixture的依赖注入就是使用Spring IoC容器的注入功能准备和销毁这些资源。可通过如下方式注入Test Fixture:
java代码:
查看复制到剪贴板打印
@Autowired
private IGoodsDao goodsDao;
@Autowired
private ApplicationContext ctx;
即可以通过Spring提供的注解实现Bean的依赖注入来完成Test Fixture的依赖注入。
三、事务管理:
开启测试类的事务管理支持,即使用Spring 容器的事务管理功能,从而可以独立于应用服务器完成事务相关功能的测试。为了使测试中的事务管理起作用需要通过如下方式开启测试类事务的支持:
java代码:
查看复制到剪贴板打印
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml"})
@TransactionConfiguration(
transactionManager = "txManager", defaultRollback=true)
public class GoodsHibernateDaoIntegrationTest {
}
Spring提供如下事务相关注解来支持事务管理:
@Transactional:使用@Transactional注解的类或方法将得到事务支持
transactionManager:指定事务管理器;
defaultRollback:是否回滚事务,默认为true表示回滚事务。
Spring还通过提供如下注解来简化事务测试:
@Transactional:使用@Transactional注解的类或方法表示需要事务支持;
@NotTransactional:只能注解方法,使用@NotTransactional注解的方法表示不需要事务支持,即不运行在事务中,Spring 3开始已不推荐使用;
@BeforeTransaction和@AfterTransaction:使用这两个注解注解的方法定义了在一个事务性测试方法之前或之后执行的行为,且被注解的方法将运行在该事务性方法的事务之外。
@Rollback(true):默认为true,用于替换@TransactionConfiguration中定义的defaultRollback指定的回滚行为。
四、常用注解支持:Spring框架提供如下注解来简化集成测试:
@DirtiesContext:表示每个测试方法执行完毕需关闭当前上下文并重建一个全新的上下文,即不缓存上下文。可应用到类或方法级别,但在JUnit 3.8中只能应用到方法级别。
@ExpectedException:表示被注解的方法预期将抛出一个异常,使用如@ExpectedException(NotCodeException.class)来指定异常,定义方式类似于Junit 4中的@Test(expected = NotCodeException.class),@ExpectedException注解和@Test(expected =……)应该两者选一。
@Repeat:表示被注解的方法应被重复执行多少次,使用如@Repeat(2)方式指定。
@Timed:表示被注解的方法必须在多长时间内运行完毕,超时将抛出异常,使用如@Timed(millis=10)方式指定,单位为毫秒。注意此处指定的时间是如下方法执行时间之和:测试方法执行时间(或者任何测试方法重复执行时间之和)、@Before和@After注解的测试方法之前和之后执行的方法执行时间。而Junit 4中的@Test(timeout=2)指定的超时时间只是测试方法执行时间,不包括任何重复等。
除了支持如上注解外,还支持【第十二章 零配置】中依赖注入等注解。
五、TestContext框架支持类:提供对测试框架的支持,如Junit、TestNG测试框架,用于集成Spring TestContext和测试框架来简化测试,TestContext框架提供如下支持类:
JUnit 3.8支持类:提供对Spring TestContext框架与Junit3.8测试框架的集成:
AbstractJUnit38SpringContextTests:我们的测试类继承该类后将获取到Test Fixture的依赖注入好处。
AbstractTransactionalJUnit38SpringContextTests:我们的测试类继承该类后除了能得到Test Fixture的依赖注入好处,还额外获取到事务管理支持。
JUnit 4.5+支持类:提供对Spring TestContext框架与Junit4.5+测试框架的集成:
AbstractJUnit4SpringContextTests:我们的测试类继承该类后将获取到Test Fixture的依赖注入好处。
AbstractTransactionalJUnit4SpringContextTests:我们的测试类继承该类后除了能得到Test Fixture的依赖注入好处,还额外获取到事务管理支持。
定制 Junit4.5+运行器:通过定制自己的Junit4.5+运行器从而无需继承JUnit 4.5+支持类即可完成需要的功能,如Test Fixture的依赖注入、事务管理支持,
@RunWith(SpringJUnit4ClassRunner.class):使用该注解注解到测试类上表示将集成Spring TestContext和Junit 4.5+测试框架。
@TestExecutionListeners:该注解用于指定TestContext框架的监听器用于与TestContext框架管理器发布的测试执行事件进行交互,TestContext框架提供如下三个默认的监听器:DependencyInjectionTestExecutionListener、DirtiesContextTestExecutionListener、TransactionalTestExecutionListener分别完成对Test Fixture的依赖注入、@DirtiesContext支持和事务管理支持,即在默认情况下将自动注册这三个监听器,另外还可以使用如下方式指定监听器:
java代码:
查看复制到剪贴板打印
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public class GoodsHibernateDaoIntegrationTest {
}
如上配置将通过定制的Junit4.5+运行器运行,但不会完成Test Fixture的依赖注入、事务管理等等,如果只需要Test Fixture的依赖注入,可以使用@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})指定。
TestNG支持类:提供对Spring TestContext框架与TestNG测试框架的集成:
AbstractTestNGSpringContextTests:我们的测试类继承该类后将获取到Test Fixture的依赖注入好处。
AbstractTransactionalTestNGSpringContextTests:我们的测试类继承该类后除了能得到Test Fixture的依赖注入好处,还额外获取到事务管理支持。
到此Spring TestContext测试框架减少完毕了,接下来让我们学习一下如何进行集成测试吧。
13.3.3 准备集成测试环境
对于集成测试环境各种配置应该和开发环境或实际生产环境配置相分离,即集成测试时应该使用单独搭建一套独立的测试环境,不应使用开发环境或实际生产环境的配置,从而保证测试环境、开发、生产环境相分离。
1、拷贝一份Spring资源配置文件applicationContext-resources.xml,并命名为applicationContext-resources-test.xml表示用于集成测试使用,并修改如下内容:
java代码:
查看复制到剪贴板打印
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:resources-test.properties</value>
</list>
</property>
</bean>
2、拷贝一份替换配置元数据的资源文件(resources/resources.properties),并命名为resources-test.properties表示用于集成测试使用,并修改为以下内容:
java代码:
查看复制到剪贴板打印
db.driver.class=org.hsqldb.jdbcDriver
db.url=jdbc:hsqldb:mem:point_shop
db.username=sa
db.password=
#Hibernate属性
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.hbm2ddl.auto=create-drop
hibernate.show_sql=false
hibernate.format_sql=true
jdbc:hsqldb:mem:point_shop:我们在集成测试时将使用HSQLDB,并采用内存数据库模式运行;
hibernate.hbm2ddl.auto=create-drop:表示在创建SessionFactory时根据Hibernate映射配置创建相应Model的表结构,并在SessionFactory关闭时删除这些表结构。
到此我们测试环境修改完毕,在进行集成测试时一定要保证测试环境、开发环境、实际生产环境相分离,即对于不同的环境使用不同的配置文件。
13.3.4 数据访问层
数据访问层集成测试,同单元测试一样目的不仅测试该层定义的接口实现方法的行为是否正确,而且还要测试是否正确与数据库交互,是否发送并执行了正确的SQL,SQL执行成功后是否正确的组装了业务逻辑层需要的数据。
数据访问层集成测试不再通过Mock对象与数据库交互的API来完成测试,而是使用实实在在存在的与数据库交互的对象来完成测试。
接下来让我们学习一下如何进行数据访问层集成测试:
1、在test文件夹下创建如下测试类:
java代码:
查看复制到剪贴板打印
package cn.javass.point.dao.hibernate;
//省略import
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml"})
@TransactionConfiguration(transactionManager = "txManager", defaultRollback=false)
public class GoodsHibernateDaoIntegrationTest {
@Autowired
private ApplicationContext ctx;
@Autowired
private IGoodsCodeDao goodsCodeDao;
}
@RunWith(SpringJUnit4ClassRunner.class):表示使用自己定制的Junit4.5+运行器来运行测试,即完成Spring TestContext框架与Junit集成;
@ContextConfiguration:指定要加载的Spring配置文件,此处注意我们的Spring资源配置文件为“applicationContext-resources-test.xml”;
@TransactionConfiguration:开启测试类的事务管理支持配置,并指定事务管理器和默认回滚行为;
@Autowired:完成Test Fixture(测试固件)的依赖注入。
2、测试支持写完后,接下来测试一下分页查询所有已发布的商品是否满足需求:
java代码:
查看复制到剪贴板打印
@Transactional
@Rollback
@Test
public void testListAllPublishedSuccess() {
GoodsModel goods = new GoodsModel();
goods.setDeleted(false);
goods.setDescription("");
goods.setName("测试商品");
goods.setPublished(true);
goodsDao.save(goods);
Assert.assertTrue(goodsDao.listAllPublished(1).size() == 1);
Assert.assertTrue(goodsDao.listAllPublished(2).size() == 0);
}
@Transactional:表示测试方法将允许在事务环境;
@Rollback:表示替换@ContextConfiguration指定的默认事务回滚行为,即将在测试方法执行完毕时回滚事务。
数据访问层的集成测试也是非常简单,与数据访问层的单元测试类似,也应该只对复杂的数据访问层代码进行测试。
13.3.5 业务逻辑层
业务逻辑层集成测试,目的同样是测试该层的业务逻辑是否正确,对于数据访问层实现通过Spring IoC容器完成装配,即使用真实的数据访问层实现来获取相应的底层数据。
接下来让我们学习一下如何进行业务逻辑层集成测试:
1、在test文件夹下创建如下测试类:
java代码:
查看复制到剪贴板打印
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml",
"classpath:cn/javass/point/service/applicationContext-service.xml"})
@TransactionConfiguration(transactionManager = "txManager", defaultRollback=false)
public class GoodsCodeServiceImplIntegrationTest extends AbstractJUnit4SpringContextTests {
@Autowired
private IGoodsCodeService goodsCodeService;
@Autowired
private IGoodsService goodsService;
}
AbstractJUnit4SpringContextTests:表示将Spring TestContext框架与Junit4.5+测试框架集成;
@ContextConfiguration:指定要加载的Spring配置文件,此处注意我们的Spring资源配置文件为“applicationContext-resources-test.xml”;
@TransactionConfiguration:开启测试类的事务管理支持配置,并指定事务管理器和默认回滚行为;
@Autowired:完成Test Fixture(测试固件)的依赖注入。
2、测试支持写完后,接下来测试一下购买商品Code码是否满足需求:
2.1、测试购买失败的场景:
java代码:
查看复制到剪贴板打印
@Transactional
@Rollback
@ExpectedException(NotCodeException.class)
@Test
public void testBuyFail() {
goodsCodeService.buy("test", 1);
}
由于我们数据库中没有相应商品的Code码,因此将抛出NotCodeException异常。
2.2、测试购买成功的场景:
java代码:
查看复制到剪贴板打印
@Transactional
@Rollback
@Test
public void testBuySuccess() {
//1.添加商品
GoodsModel goods = new GoodsModel();
goods.setDeleted(false);
goods.setDescription("");
goods.setName("测试商品");
goods.setPublished(true);
goodsService.save(goods);
//2.添加商品Code码
GoodsCodeModel goodsCode = new GoodsCodeModel();
goodsCode.setGoods(goods);
goodsCode.setCode("test");
goodsCodeService.save(goodsCode);
//3.测试购买商品Code码
GoodsCodeModel resultGoodsCode = goodsCodeService.buy("test", 1);
Assert.assertEquals(goodsCode.getId(), resultGoodsCode.getId());
}
由于我们添加了指定商品的Code码因此购买将成功,如果失败说明业务写错了,应该重写。
业务逻辑层的集成测试也是非常简单,与业务逻辑层的单元测试类似,也应该只对复杂的业务逻辑层代码进行测试。
13.3.5 表现层
对于表现层集成测试,同样类似于单元测试,但对于业务逻辑层都将使用真实的实现,而不再是通过Mock对象来测试,这也是集成测试和单元测试的区别。
接下来让我们学习一下如何进行表现层Action集成测试:
1、准备Struts提供的junit插件, 到struts-2.2.1.1.zip中拷贝如下jar包到类路径:
lib\struts2-junit-plugin-2.2.1.1.jar
2、测试支持类:Struts2提供StrutsSpringTestCase测试支持类,我们所有的Action测试类都需要继承该类;
3、准备Spring配置文件:由于我们的测试类继承StrutsSpringTestCase且将通过覆盖该类的getContextLocations方法来指定Spring配置文件,但由于getContextLocations方法只能返回一个配置文件,因此我们需要新建一个用于导入其他Spring配置文件的配置文件applicationContext-test.xml,具体内容如下:
java代码:
查看复制到剪贴板打印
<import resource="classpath:applicationContext-resources-test.xml"/>
<import resource="classpath:cn/javass/point/dao/applicationContext-hibernate.xml"/>
<import resource="classpath:cn/javass/point/service/applicationContext-service.xml"/>
<import resource="classpath:cn/javass/point/web/pointShop-admin-servlet.xml"/>
<import resource="classpath:cn/javass/point/web/pointShop-front-servlet.xml"/>
3、在test文件夹下创建如下测试类:
java代码:
查看复制到剪贴板打印
package cn.javass.point.web.front;
//省略import
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public class GoodsActionIntegrationTest extends StrutsSpringTestCase {
@Override
protected String getContextLocations() {
return "classpath:applicationContext-test.xml";
}
@Before
public void setUp() throws Exception {
//1 指定Struts2配置文件
//该方式等价于通过web.xml中的<init-param>方式指定参数
Map<String, String> dispatcherInitParams = new HashMap<String, String>();
ReflectionTestUtils.setField(this, "dispatcherInitParams", dispatcherInitParams);
//1.1 指定Struts配置文件位置
dispatcherInitParams.put("config", "struts-default.xml,struts-plugin.xml,struts.xml");
super.setUp();
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
}
@RunWith(SpringJUnit4ClassRunner.class):表示使用自己定制的Junit4.5+运行器来运行测试,即完成Spring TestContext框架与Junit集成;
@TestExecutionListeners({}):没有指定任何监听器,即不会自动完成对Test Fixture的依赖注入、@DirtiesContext支持和事务管理支持;
StrutsSpringTestCase:集成测试Struts2+Spring时所有集成测试类必须继承该类;
setUp方法:在每个测试方法之前都执行的初始化方法,其中dispatcherInitParams用于指定等价于在web.xml中的<init-param>方式指定的参数;必须调用super.setUp()用于初始化Struts2和Spring环境。
tearDown():在每个测试方法之前都执行的销毁方法,必须调用super.tearDown()来销毁Spring容器等。
4、测试支持写完后,接下来测试一下前台购买商品Code码是否满足需求:
4.1、测试购买失败的场景:
java代码:
查看复制到剪贴板打印
@Test
public void testBuyFail() throws UnsupportedEncodingException, ServletException {
//2 前台购买商品失败
//2.1 首先重置hhtp相关对象,并准备准备请求参数
initServletMockObjects();
request.setParameter("goodsId", String.valueOf(Integer.MIN_VALUE));
//2.2 调用前台GoodsAction的buy方法完成购买相应商品的Code码
executeAction("/goods/buy.action");
GoodsAction frontGoodsAction = (GoodsAction) ActionContext.getContext().getActionInvocation().getAction();
//2.3 验证前台GoodsAction的buy方法有错误
Assert.assertTrue(frontGoodsAction.getActionErrors().size() > 0);
}
initServletMockObjects():用于重置所有http相关对象,如request等;
request.setParameter("goodsId", String.valueOf(Integer.MIN_VALUE)):用于准备请求参数;
executeAction("/goods/buy.action"):通过模拟http请求来调用前台GoodsAction的buy方法完成商品购买
Assert.assertTrue(frontGoodsAction.getActionErrors().size() > 0):表示执行Action时有错误,即Action动作错误。如果条件不成立,说明我们Action功能是错误的,需要修改。
4.2、测试购买成功的场景:
java代码:
查看复制到剪贴板打印
@Test
public void testBuySuccess() throws UnsupportedEncodingException, ServletException {
//3 后台新增商品
//3.1 准备请求参数
request.setParameter("goods.name", "测试商品");
request.setParameter("goods.description", "测试商品描述");
request.setParameter("goods.originalPoint", "1");
request.setParameter("goods.nowPoint", "2");
request.setParameter("goods.published", "true");
//3.2 调用后台GoodsAction的add方法完成新增
executeAction("/admin/goods/add.action");
//2.3 获取GoodsAction的goods属性
GoodsModel goods = (GoodsModel) findValueAfterExecute("goods");
//4 后台新增商品Code码
//4.1 首先重置hhtp相关对象,并准备准备请求参数
initServletMockObjects();
request.setParameter("goodsId", String.valueOf(goods.getId()));
request.setParameter("codes", "a\rb");
//4.2 调用后台GoodsCodeAction的add方法完成新增商品Code码
executeAction("/admin/goodsCode/add.action");
//5 前台购买商品成功
//5.1 首先重置hhtp相关对象,并准备准备请求参数
initServletMockObjects();
request.setParameter("goodsId", String.valueOf(goods.getId()));
//5.2 调用前台GoodsAction的buy方法完成购买相应商品的Code码
executeAction("/goods/buy.action");
GoodsAction frontGoodsAction = (GoodsAction) ActionContext.getContext().getActionInvocation().getAction();
//5.3 验证前台GoodsAction的buy方法没有错误
Assert.assertTrue(frontGoodsAction.getActionErrors().size() == 0);
}
executeAction("/admin/goods/add.action"):调用后台GoodsAction的add方法,用于新增商品;
executeAction("/admin/goodsCode/add.action"):调用后台GoodCodeAction的add方法用于新增商品Code码;
executeAction("/goods/buy.action"):调用前台GoodsAction的buy方法,用于购买相应商品,其中Assert.assertTrue(frontGoodsAction.getActionErrors().size() == 0)表示购买成功,即Action动作正确。
表现层Action集成测试介绍就到此为止,如何深入StrutsSpringTestCase来完成集成测试已超出本书范围,如果读者对这部分感兴趣可以到Struts2官网学习最新的测试技巧。
13.3 集成测试
13.3.1 概述
集成测试是在单元测试之上,通常是将一个或多个已进行过单元测试的组件组合起来完成的,即集成测试中一般不会出现Mock对象,都是实实在在的真实实现。
对于单元测试,如前边在进行数据访问层单元测试时,通过Mock HibernateTemplate对象然后将其注入到相应的DAO实现,此时单元测试只测试某层的某个功能是否正确,对其他层如何提供服务采用Mock方式提供。
对于集成测试,如要进行数据访问层集成测试时,需要实实在在的HibernateTemplate对象然后将其注入到相应的DAO实现,此时集成测试将不仅测试该层功能是否正确,还将测试服务提供者提供的服务是否正确执行。
使用Spring的一个好处是能非常简单的进行集成测试,无需依赖web服务器或应用服务器即可完成测试。Spring通过提供一套TestContext框架来简化集成测试,使用TestContext测试框架能获得许多好处,如Spring IoC容器缓存、事务管理、依赖注入、Spring测试支持类等等。
13.3.2 Spring TestContext框架支持
Spring TestContext框架提供了一些通用的集成测试支持,主要提供如下支持:
一、上下文管理及缓存:
对于每一个测试用例(测试类)应该只有一个上下文,而不是每个测试方法都创建新的上下文,这样有助于减少启动容器的开销,提供测试效率。可通过如下方式指定要加载的上下文:
java代码:
查看复制到剪贴板打印
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml"})
public class GoodsHibernateDaoIntegrationTest {
}
locations:指定Spring配置文件位置;
inheritLocations:如果设置为false,将屏蔽掉父类中使用该注解指定的配置文件位置,默认为true表示继承父类中使用该注解指定的配置文件位置。
二、Test Fixture(测试固件)的依赖注入:
Test Fixture可以指运行测试时需要的任何东西,一般通过@Before定义的初始化Fixture方法准备这些资源,而通过@After定义的销毁Fixture方法销毁或还原这些资源。
Test Fixture的依赖注入就是使用Spring IoC容器的注入功能准备和销毁这些资源。可通过如下方式注入Test Fixture:
java代码:
查看复制到剪贴板打印
@Autowired
private IGoodsDao goodsDao;
@Autowired
private ApplicationContext ctx;
即可以通过Spring提供的注解实现Bean的依赖注入来完成Test Fixture的依赖注入。
三、事务管理:
开启测试类的事务管理支持,即使用Spring 容器的事务管理功能,从而可以独立于应用服务器完成事务相关功能的测试。为了使测试中的事务管理起作用需要通过如下方式开启测试类事务的支持:
java代码:
查看复制到剪贴板打印
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml"})
@TransactionConfiguration(
transactionManager = "txManager", defaultRollback=true)
public class GoodsHibernateDaoIntegrationTest {
}
Spring提供如下事务相关注解来支持事务管理:
@Transactional:使用@Transactional注解的类或方法将得到事务支持
transactionManager:指定事务管理器;
defaultRollback:是否回滚事务,默认为true表示回滚事务。
Spring还通过提供如下注解来简化事务测试:
@Transactional:使用@Transactional注解的类或方法表示需要事务支持;
@NotTransactional:只能注解方法,使用@NotTransactional注解的方法表示不需要事务支持,即不运行在事务中,Spring 3开始已不推荐使用;
@BeforeTransaction和@AfterTransaction:使用这两个注解注解的方法定义了在一个事务性测试方法之前或之后执行的行为,且被注解的方法将运行在该事务性方法的事务之外。
@Rollback(true):默认为true,用于替换@TransactionConfiguration中定义的defaultRollback指定的回滚行为。
四、常用注解支持:Spring框架提供如下注解来简化集成测试:
@DirtiesContext:表示每个测试方法执行完毕需关闭当前上下文并重建一个全新的上下文,即不缓存上下文。可应用到类或方法级别,但在JUnit 3.8中只能应用到方法级别。
@ExpectedException:表示被注解的方法预期将抛出一个异常,使用如@ExpectedException(NotCodeException.class)来指定异常,定义方式类似于Junit 4中的@Test(expected = NotCodeException.class),@ExpectedException注解和@Test(expected =……)应该两者选一。
@Repeat:表示被注解的方法应被重复执行多少次,使用如@Repeat(2)方式指定。
@Timed:表示被注解的方法必须在多长时间内运行完毕,超时将抛出异常,使用如@Timed(millis=10)方式指定,单位为毫秒。注意此处指定的时间是如下方法执行时间之和:测试方法执行时间(或者任何测试方法重复执行时间之和)、@Before和@After注解的测试方法之前和之后执行的方法执行时间。而Junit 4中的@Test(timeout=2)指定的超时时间只是测试方法执行时间,不包括任何重复等。
除了支持如上注解外,还支持【第十二章 零配置】中依赖注入等注解。
五、TestContext框架支持类:提供对测试框架的支持,如Junit、TestNG测试框架,用于集成Spring TestContext和测试框架来简化测试,TestContext框架提供如下支持类:
JUnit 3.8支持类:提供对Spring TestContext框架与Junit3.8测试框架的集成:
AbstractJUnit38SpringContextTests:我们的测试类继承该类后将获取到Test Fixture的依赖注入好处。
AbstractTransactionalJUnit38SpringContextTests:我们的测试类继承该类后除了能得到Test Fixture的依赖注入好处,还额外获取到事务管理支持。
JUnit 4.5+支持类:提供对Spring TestContext框架与Junit4.5+测试框架的集成:
AbstractJUnit4SpringContextTests:我们的测试类继承该类后将获取到Test Fixture的依赖注入好处。
AbstractTransactionalJUnit4SpringContextTests:我们的测试类继承该类后除了能得到Test Fixture的依赖注入好处,还额外获取到事务管理支持。
定制 Junit4.5+运行器:通过定制自己的Junit4.5+运行器从而无需继承JUnit 4.5+支持类即可完成需要的功能,如Test Fixture的依赖注入、事务管理支持,
@RunWith(SpringJUnit4ClassRunner.class):使用该注解注解到测试类上表示将集成Spring TestContext和Junit 4.5+测试框架。
@TestExecutionListeners:该注解用于指定TestContext框架的监听器用于与TestContext框架管理器发布的测试执行事件进行交互,TestContext框架提供如下三个默认的监听器:DependencyInjectionTestExecutionListener、DirtiesContextTestExecutionListener、TransactionalTestExecutionListener分别完成对Test Fixture的依赖注入、@DirtiesContext支持和事务管理支持,即在默认情况下将自动注册这三个监听器,另外还可以使用如下方式指定监听器:
java代码:
查看复制到剪贴板打印
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public class GoodsHibernateDaoIntegrationTest {
}
如上配置将通过定制的Junit4.5+运行器运行,但不会完成Test Fixture的依赖注入、事务管理等等,如果只需要Test Fixture的依赖注入,可以使用@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})指定。
TestNG支持类:提供对Spring TestContext框架与TestNG测试框架的集成:
AbstractTestNGSpringContextTests:我们的测试类继承该类后将获取到Test Fixture的依赖注入好处。
AbstractTransactionalTestNGSpringContextTests:我们的测试类继承该类后除了能得到Test Fixture的依赖注入好处,还额外获取到事务管理支持。
到此Spring TestContext测试框架减少完毕了,接下来让我们学习一下如何进行集成测试吧。
13.3.3 准备集成测试环境
对于集成测试环境各种配置应该和开发环境或实际生产环境配置相分离,即集成测试时应该使用单独搭建一套独立的测试环境,不应使用开发环境或实际生产环境的配置,从而保证测试环境、开发、生产环境相分离。
1、拷贝一份Spring资源配置文件applicationContext-resources.xml,并命名为applicationContext-resources-test.xml表示用于集成测试使用,并修改如下内容:
java代码:
查看复制到剪贴板打印
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:resources-test.properties</value>
</list>
</property>
</bean>
2、拷贝一份替换配置元数据的资源文件(resources/resources.properties),并命名为resources-test.properties表示用于集成测试使用,并修改为以下内容:
java代码:
查看复制到剪贴板打印
db.driver.class=org.hsqldb.jdbcDriver
db.url=jdbc:hsqldb:mem:point_shop
db.username=sa
db.password=
#Hibernate属性
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.hbm2ddl.auto=create-drop
hibernate.show_sql=false
hibernate.format_sql=true
jdbc:hsqldb:mem:point_shop:我们在集成测试时将使用HSQLDB,并采用内存数据库模式运行;
hibernate.hbm2ddl.auto=create-drop:表示在创建SessionFactory时根据Hibernate映射配置创建相应Model的表结构,并在SessionFactory关闭时删除这些表结构。
到此我们测试环境修改完毕,在进行集成测试时一定要保证测试环境、开发环境、实际生产环境相分离,即对于不同的环境使用不同的配置文件。
13.3.4 数据访问层
数据访问层集成测试,同单元测试一样目的不仅测试该层定义的接口实现方法的行为是否正确,而且还要测试是否正确与数据库交互,是否发送并执行了正确的SQL,SQL执行成功后是否正确的组装了业务逻辑层需要的数据。
数据访问层集成测试不再通过Mock对象与数据库交互的API来完成测试,而是使用实实在在存在的与数据库交互的对象来完成测试。
接下来让我们学习一下如何进行数据访问层集成测试:
1、在test文件夹下创建如下测试类:
java代码:
查看复制到剪贴板打印
package cn.javass.point.dao.hibernate;
//省略import
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml"})
@TransactionConfiguration(transactionManager = "txManager", defaultRollback=false)
public class GoodsHibernateDaoIntegrationTest {
@Autowired
private ApplicationContext ctx;
@Autowired
private IGoodsCodeDao goodsCodeDao;
}
@RunWith(SpringJUnit4ClassRunner.class):表示使用自己定制的Junit4.5+运行器来运行测试,即完成Spring TestContext框架与Junit集成;
@ContextConfiguration:指定要加载的Spring配置文件,此处注意我们的Spring资源配置文件为“applicationContext-resources-test.xml”;
@TransactionConfiguration:开启测试类的事务管理支持配置,并指定事务管理器和默认回滚行为;
@Autowired:完成Test Fixture(测试固件)的依赖注入。
2、测试支持写完后,接下来测试一下分页查询所有已发布的商品是否满足需求:
java代码:
查看复制到剪贴板打印
@Transactional
@Rollback
@Test
public void testListAllPublishedSuccess() {
GoodsModel goods = new GoodsModel();
goods.setDeleted(false);
goods.setDescription("");
goods.setName("测试商品");
goods.setPublished(true);
goodsDao.save(goods);
Assert.assertTrue(goodsDao.listAllPublished(1).size() == 1);
Assert.assertTrue(goodsDao.listAllPublished(2).size() == 0);
}
@Transactional:表示测试方法将允许在事务环境;
@Rollback:表示替换@ContextConfiguration指定的默认事务回滚行为,即将在测试方法执行完毕时回滚事务。
数据访问层的集成测试也是非常简单,与数据访问层的单元测试类似,也应该只对复杂的数据访问层代码进行测试。
13.3.5 业务逻辑层
业务逻辑层集成测试,目的同样是测试该层的业务逻辑是否正确,对于数据访问层实现通过Spring IoC容器完成装配,即使用真实的数据访问层实现来获取相应的底层数据。
接下来让我们学习一下如何进行业务逻辑层集成测试:
1、在test文件夹下创建如下测试类:
java代码:
查看复制到剪贴板打印
@ContextConfiguration(
locations={"classpath:applicationContext-resources-test.xml",
"classpath:cn/javass/point/dao/applicationContext-hibernate.xml",
"classpath:cn/javass/point/service/applicationContext-service.xml"})
@TransactionConfiguration(transactionManager = "txManager", defaultRollback=false)
public class GoodsCodeServiceImplIntegrationTest extends AbstractJUnit4SpringContextTests {
@Autowired
private IGoodsCodeService goodsCodeService;
@Autowired
private IGoodsService goodsService;
}
AbstractJUnit4SpringContextTests:表示将Spring TestContext框架与Junit4.5+测试框架集成;
@ContextConfiguration:指定要加载的Spring配置文件,此处注意我们的Spring资源配置文件为“applicationContext-resources-test.xml”;
@TransactionConfiguration:开启测试类的事务管理支持配置,并指定事务管理器和默认回滚行为;
@Autowired:完成Test Fixture(测试固件)的依赖注入。
2、测试支持写完后,接下来测试一下购买商品Code码是否满足需求:
2.1、测试购买失败的场景:
java代码:
查看复制到剪贴板打印
@Transactional
@Rollback
@ExpectedException(NotCodeException.class)
@Test
public void testBuyFail() {
goodsCodeService.buy("test", 1);
}
由于我们数据库中没有相应商品的Code码,因此将抛出NotCodeException异常。
2.2、测试购买成功的场景:
java代码:
查看复制到剪贴板打印
@Transactional
@Rollback
@Test
public void testBuySuccess() {
//1.添加商品
GoodsModel goods = new GoodsModel();
goods.setDeleted(false);
goods.setDescription("");
goods.setName("测试商品");
goods.setPublished(true);
goodsService.save(goods);
//2.添加商品Code码
GoodsCodeModel goodsCode = new GoodsCodeModel();
goodsCode.setGoods(goods);
goodsCode.setCode("test");
goodsCodeService.save(goodsCode);
//3.测试购买商品Code码
GoodsCodeModel resultGoodsCode = goodsCodeService.buy("test", 1);
Assert.assertEquals(goodsCode.getId(), resultGoodsCode.getId());
}
由于我们添加了指定商品的Code码因此购买将成功,如果失败说明业务写错了,应该重写。
业务逻辑层的集成测试也是非常简单,与业务逻辑层的单元测试类似,也应该只对复杂的业务逻辑层代码进行测试。
13.3.5 表现层
对于表现层集成测试,同样类似于单元测试,但对于业务逻辑层都将使用真实的实现,而不再是通过Mock对象来测试,这也是集成测试和单元测试的区别。
接下来让我们学习一下如何进行表现层Action集成测试:
1、准备Struts提供的junit插件, 到struts-2.2.1.1.zip中拷贝如下jar包到类路径:
lib\struts2-junit-plugin-2.2.1.1.jar
2、测试支持类:Struts2提供StrutsSpringTestCase测试支持类,我们所有的Action测试类都需要继承该类;
3、准备Spring配置文件:由于我们的测试类继承StrutsSpringTestCase且将通过覆盖该类的getContextLocations方法来指定Spring配置文件,但由于getContextLocations方法只能返回一个配置文件,因此我们需要新建一个用于导入其他Spring配置文件的配置文件applicationContext-test.xml,具体内容如下:
java代码:
查看复制到剪贴板打印
<import resource="classpath:applicationContext-resources-test.xml"/>
<import resource="classpath:cn/javass/point/dao/applicationContext-hibernate.xml"/>
<import resource="classpath:cn/javass/point/service/applicationContext-service.xml"/>
<import resource="classpath:cn/javass/point/web/pointShop-admin-servlet.xml"/>
<import resource="classpath:cn/javass/point/web/pointShop-front-servlet.xml"/>
3、在test文件夹下创建如下测试类:
java代码:
查看复制到剪贴板打印
package cn.javass.point.web.front;
//省略import
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public class GoodsActionIntegrationTest extends StrutsSpringTestCase {
@Override
protected String getContextLocations() {
return "classpath:applicationContext-test.xml";
}
@Before
public void setUp() throws Exception {
//1 指定Struts2配置文件
//该方式等价于通过web.xml中的<init-param>方式指定参数
Map<String, String> dispatcherInitParams = new HashMap<String, String>();
ReflectionTestUtils.setField(this, "dispatcherInitParams", dispatcherInitParams);
//1.1 指定Struts配置文件位置
dispatcherInitParams.put("config", "struts-default.xml,struts-plugin.xml,struts.xml");
super.setUp();
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
}
@RunWith(SpringJUnit4ClassRunner.class):表示使用自己定制的Junit4.5+运行器来运行测试,即完成Spring TestContext框架与Junit集成;
@TestExecutionListeners({}):没有指定任何监听器,即不会自动完成对Test Fixture的依赖注入、@DirtiesContext支持和事务管理支持;
StrutsSpringTestCase:集成测试Struts2+Spring时所有集成测试类必须继承该类;
setUp方法:在每个测试方法之前都执行的初始化方法,其中dispatcherInitParams用于指定等价于在web.xml中的<init-param>方式指定的参数;必须调用super.setUp()用于初始化Struts2和Spring环境。
tearDown():在每个测试方法之前都执行的销毁方法,必须调用super.tearDown()来销毁Spring容器等。
4、测试支持写完后,接下来测试一下前台购买商品Code码是否满足需求:
4.1、测试购买失败的场景:
java代码:
查看复制到剪贴板打印
@Test
public void testBuyFail() throws UnsupportedEncodingException, ServletException {
//2 前台购买商品失败
//2.1 首先重置hhtp相关对象,并准备准备请求参数
initServletMockObjects();
request.setParameter("goodsId", String.valueOf(Integer.MIN_VALUE));
//2.2 调用前台GoodsAction的buy方法完成购买相应商品的Code码
executeAction("/goods/buy.action");
GoodsAction frontGoodsAction = (GoodsAction) ActionContext.getContext().getActionInvocation().getAction();
//2.3 验证前台GoodsAction的buy方法有错误
Assert.assertTrue(frontGoodsAction.getActionErrors().size() > 0);
}
initServletMockObjects():用于重置所有http相关对象,如request等;
request.setParameter("goodsId", String.valueOf(Integer.MIN_VALUE)):用于准备请求参数;
executeAction("/goods/buy.action"):通过模拟http请求来调用前台GoodsAction的buy方法完成商品购买
Assert.assertTrue(frontGoodsAction.getActionErrors().size() > 0):表示执行Action时有错误,即Action动作错误。如果条件不成立,说明我们Action功能是错误的,需要修改。
4.2、测试购买成功的场景:
java代码:
查看复制到剪贴板打印
@Test
public void testBuySuccess() throws UnsupportedEncodingException, ServletException {
//3 后台新增商品
//3.1 准备请求参数
request.setParameter("goods.name", "测试商品");
request.setParameter("goods.description", "测试商品描述");
request.setParameter("goods.originalPoint", "1");
request.setParameter("goods.nowPoint", "2");
request.setParameter("goods.published", "true");
//3.2 调用后台GoodsAction的add方法完成新增
executeAction("/admin/goods/add.action");
//2.3 获取GoodsAction的goods属性
GoodsModel goods = (GoodsModel) findValueAfterExecute("goods");
//4 后台新增商品Code码
//4.1 首先重置hhtp相关对象,并准备准备请求参数
initServletMockObjects();
request.setParameter("goodsId", String.valueOf(goods.getId()));
request.setParameter("codes", "a\rb");
//4.2 调用后台GoodsCodeAction的add方法完成新增商品Code码
executeAction("/admin/goodsCode/add.action");
//5 前台购买商品成功
//5.1 首先重置hhtp相关对象,并准备准备请求参数
initServletMockObjects();
request.setParameter("goodsId", String.valueOf(goods.getId()));
//5.2 调用前台GoodsAction的buy方法完成购买相应商品的Code码
executeAction("/goods/buy.action");
GoodsAction frontGoodsAction = (GoodsAction) ActionContext.getContext().getActionInvocation().getAction();
//5.3 验证前台GoodsAction的buy方法没有错误
Assert.assertTrue(frontGoodsAction.getActionErrors().size() == 0);
}
executeAction("/admin/goods/add.action"):调用后台GoodsAction的add方法,用于新增商品;
executeAction("/admin/goodsCode/add.action"):调用后台GoodCodeAction的add方法用于新增商品Code码;
executeAction("/goods/buy.action"):调用前台GoodsAction的buy方法,用于购买相应商品,其中Assert.assertTrue(frontGoodsAction.getActionErrors().size() == 0)表示购买成功,即Action动作正确。
表现层Action集成测试介绍就到此为止,如何深入StrutsSpringTestCase来完成集成测试已超出本书范围,如果读者对这部分感兴趣可以到Struts2官网学习最新的测试技巧。
相关推荐
而这次我们要探讨的是Spring Framework 2.5.6版本,它包含了对JUnit 4.4和Spring Test的支持,这使得测试驱动开发(TDD)在Spring项目中变得更加得心应手。 Spring Framework 2.5.6是该框架的一个里程碑版本,它...
Spring框架提供了Spring Test模块,专门用于支持Spring应用程序的测试,而Spring Test 3.2.9是其中的一个版本,它针对JUnit进行了深度整合,使得开发者能够更方便、更高效地进行测试驱动开发(TDD)。 1. **Spring ...
《Spring Test:深入理解与实践》 在Java开发领域,Spring框架无疑是最为广泛使用的轻量级框架之一,而Spring Test则是Spring框架的重要组成部分,它为开发者提供了强大的单元测试和集成测试工具。本文将深入探讨...
Spring Test是Spring框架的一部分,专为测试Spring应用而设计,它提供了丰富的功能,使得开发者能够更轻松、更高效地对Spring驱动的应用进行单元测试和集成测试。在本篇中,我们将深入探讨Spring Test的关键概念、...
6. Test:提供单元测试和集成测试的支持,如 TestContext、SpringJUnit4ClassRunner 等,便于进行 TDD(Test-Driven Development)。 三、关键特性 1. 容器扩展:Spring 提供了 BeanPostProcessor 和 ...
7. **Test Support**:Spring的测试框架支持单元测试和集成测试,提供了模拟对象、数据源配置和事务管理等功能,方便进行测试驱动开发(TDD)。 8. **WebSocket支持**:Spring Framework 4.3版本开始支持WebSocket...
7. **测试支持**:Spring 提供了强大的单元测试和集成测试工具,如 Spring Test 和 Spring Boot Test,方便开发者进行测试驱动开发(TDD)和行为驱动开发(BDD)。 8. **Spring Boot**:虽然不是直接包含在 4.2.4....
首先,Spring Test模块的核心是`spring-test` jar,它提供了与Spring IoC容器集成的测试支持。通过这个jar包,我们可以直接在测试中注入bean,无需手动创建对象,这极大地简化了依赖管理。例如,你可以使用`@...
在编程领域,Test-Driven Development(TDD,测试驱动开发)是一种软件开发方法,它强调先编写测试用例,再编写满足这些测试用例的代码。在这个名为"spring-boot-tdd-example"的项目中,我们将深入探讨如何结合TDD...
现在,我们深入到压缩包内的两个子文件:`spring-mvc-showcase`和`spring-test-mvc-htmlunit`。 1. `spring-mvc-showcase`: 这很可能是Spring MVC的一个演示项目,展示了如何使用Spring MVC构建Web应用程序。Spring...
- **Test**:支持单元测试和集成测试,简化测试编写。 3. **新特性与改进** - **Java 8支持**:4.3.x系列版本加强了对Java 8特性的支持,如Lambda表达式、日期时间API等。 - **更友好的API**:对部分API进行了...
5. **Test框架**:Spring提供了单元测试和集成测试的支持,使得测试驱动开发(TDD)变得简单易行。 三、4.2.2.RELEASE版本亮点 1. **性能优化**:4.2.2.RELEASE版本在性能上进行了优化,提高了容器启动速度和应用...
TDD代码测试 您需要编写一个程序,该程序可以通过许多不同的属性来过滤应用程序请求日志摘录。 日志提取文件包含标头行,后跟零个或多个数据行,以逗号分隔的值格式。 第一列是发出请求的时间的Unix时间戳,第二列...
6. **测试**:Spring提供了丰富的测试工具,包括单元测试、集成测试,以及模拟对象,便于进行TDD(Test-Driven Development,测试驱动开发)。 7. **Spring Boot**:这是一个快速启动Spring应用的工具,它简化了...
Spring框架提供了内置的测试支持,包括`spring-test`模块,它为Spring应用提供了全面的测试工具。这个模块包含了JUnit和Mockito等测试库的整合,使得开发者能够方便地编写针对Spring组件的测试代码。 2. **单元...
测试文件可能位于`src/test`目录下,通常遵循TDD原则,每个功能或组件都有相应的测试用例。 在这个项目中,Spring作为后端框架,提供了服务端的功能,如数据处理、业务逻辑以及与数据库的交互。Spring Boot简化了...
Spring框架还支持测试,提供Spring Test和Spring Boot Test Suite,使得单元测试和集成测试变得更加便捷。测试驱动开发(TDD)在Spring环境中得到很好的支持,有助于提高代码质量。 除此之外,Spring Framework与...
标题 "springBootTest.zip" 暗示我们关注的是与Spring Boot相关的测试知识。Spring Boot是Java领域的一个流行框架,它简化了创建独立、生产级别的基于Spring的应用程序。在这个压缩包中,我们很可能是找到了一个使用...
Spring Boot REST API TDD 演示REST API的Spring Boot应用程序是测试优先开发的。 使用1个域模型 1个控制器,执行2个动作 使用本地 MySql数据库请参阅src/main/resources/{application,application-test}....
"spring-common-test"作为其子模块,进一步丰富了测试工具集,帮助开发者更好地进行测试驱动开发(TDD)或行为驱动开发(BDD)。 二、核心组件与功能 1. `TestContext`框架:这是Spring测试的基础,它提供了一种...