`
universsky
  • 浏览: 99302 次
文章分类
社区版块
存档分类
最新评论

Spring下的单元测试

 
阅读更多

Spring下的单元测试

1) Spring简介

Spring是一个全方位的应用程序开发框架(framework),是潜在的一站式解决方案,它定位于与典型应用相关的大部分基础结构。自从2003年发布以来,Spring Framework已经对Java企业应用体系产生了前所未有的冲击,尽管历史不长,但它拥有深厚的历史根基。如今Spring已风靡全球,甚至有取代EJB的趋势,最新的EJB3.0规范也吸取了Spring的设计理念,如今这陈风也刮到了华为公司,越来越多的项目正在使用或准备使用Spring架构开发,所以有关Spring架构下的单元测试如何做是我们必须面对的问题。简单说来,Spring有以下特性:

u 轻量级

相对于一些重量级的EJB容器,Spring的核心包在文件容量上只有不到1MB的大小,而使用Spring核心包所需要的资源负担也是很小的。

u 非侵入性

就是说你的开发对Spring的依赖很小,只需要较少的Spring API调用,甚至你的对象完全感知不到Spring容器的存在,提高了对象在不同容器环境下移植的可能性。

u 完全开放性

Spring并不排斥已有的软件结构,如StrutsEJBHibernate等,能够将已有系统很好地集成进Spring

2) Spring实现的两个核心技术

u IoC—Inversion of Control

中文翻译为控制反转,在Spring里的实现是Dependency Injection依赖注入),就是说对象之间的依赖关系在后期通过配置文件(典型为XML文件)生成, Spring里实现了两种注入方式:构造函数注入、Setter方法注入。我们可以这样理解这种技术带来的好处,前期我们只需要关注单个对象(组件)的功能实现,具体的业务实现是通过后期配置出来的,不同的配置可以产生不同的业务功能。

u AOP—Aspect-oriented programming

面向方面的编程,但我觉得翻译为面向切面的编程更容易理解一些。AOP大大降低了对象之间的耦合程度,与IoC一样,能够通过后期的配置动态为对象增加新的特性,甚至能够为对象动态增加方法。在Spring下,AOP的实现不需要借助专门的AOP定义语言,只需要普通的Java对象和XML配置文件即可。

3) Spring提供的单元测试支持

首先要说明的是,在Spring里将单元测试的对象理解为一个孤立的单元,单元依赖的对象用桩取代。但考虑到业软的开发现状,如果对象功能逻辑简单,我们将多个对象的组合作为一个被测单元(在Spring里理解为集成测试),典型的情况如对访问数据库代码的测试。

Spring架构带来的直接好处是对象之间的松耦合,减少了对象之间的依赖,这为我们做单元测试提供了便利,另外Spring基于JUnit提供了单元测试支持,实现包为spring-mock.jarSpring基于JunitTestCase类实现了两个子类:AbstractDependencyInjectionSpringContextTestsAbstractTransactionalSpringContextTests。下面我们分别讲解这两个类的使用。

u AbstractDependencyInjectionSpringContextTests

AbstractDependencyInjectionSpringContextTests 继承自JUnitTestCase,所以写测试用例的方法与以前相同。Spring下的对象之间的关系是通过XML配置文件生成的,在运行时根据XML中的配置生成对象及对象之间的关系,形成Spring上下文件环境(Application Context),做单元测试时也一样,我们基于类AbstractDependencyInjectionSpringContextTests生成测试用例时需要实现方法getConfigLocations,告诉Spring你的XML配置文件在哪儿,如下所示:

@Override

protected String[] getConfigLocations()

{

returnnew String[]{"file:D:/workspace321/example/beans-config.xml"};

}

在每个用例运行前都生成一次Spring上下文势必会影响性能,Spring在不同的用例执行间提供Spring上下文缓存功能。另外基类提供protectedapplicationContext对象,方便你访问上下文环境,如get一个Bean等。

另外,对于被测的对象可以通过依赖注入,不需要你在测试代码中显式创建,如下例所示:

publicclass UserDaoTest2 extends AbstractDependencyInjectionSpringContextTests

{

// 这个实例将被(自动的)依赖注入

private UserDao userDao;

// 依赖注入的Setter方法

publicvoid setUserDao(UserDao userDao)

{

this.userDao = userDao;

}

publicvoid testInsert()

{

User user = new User();

user.setId(1);

user.setName("tzs");

user.setAge(32);

userDao.insert(user);

}

@Override

protected String[] getConfigLocations()

{

returnnew String[] { "file:D:/workspace321/example/beans-config.xml" };

}

}

beans-config.xml文件中需要定义你的被测对象:

<bean id="userDao" class="spring.UserDao">

<property name="dataSource">

<ref bean="dataSource"/>

</property>

</bean>

Spring根据类型匹配原则(类型是UserDao)自动将userDao对象注入到测试用例对象中。

u AbstractTransactionalSpringContextTests

AbstractTransactionalSpringContextTests继承自AbstractDependencyInjectionSpringContextTests,提供事务支持功能,主要用于我们针对访问数据库代码的测试,它的最大特点是在每一个用例执行前开始一下事务,在用例执行结束后对事务回滚,也就是说用例执行期间对数据库的操作在执行结束后回退到最初的状态,用例之间的数据库环境互不影响。前面的代码基类换成AbstractTransactionalSpringContextTests,其它什么都不变,即可实现事务支持。

4) Spring如何与DBUnit结合

由于Java不可以同时继承自两个基类,所以我们的用例类不可能同时继承自DBTestCaseAbstractTransactionalSpringContextTests,但我们在“DBUnit数据库测试工具”一节最后提到也可以不需要继承自DBTestCase也能完成数据库的测试,所以为使用DBUnit功能,我们在Spring中也采用此种方式。但要注意的是为了能将DBUnit对数据库的操作纳入Spring的事务支持,不能直接从dataSource获得connection,而要通过DataSourceUtils提供的静态方法间接地获取,最后要记得将connection释放。请参见以下的例子:

publicclass UserDaoTest3 extends AbstractTransactionalSpringContextTests

{

private UserDao userDao;

publicvoid setUserDao(UserDao userDao)

{

this.userDao = userDao;

}

publicvoid testInsert() throws Exception

{

Connection jdbcConnection = null;

DataSource dataSource = (DataSource)applicationContext.getBean("dataSource");

//获得connection对象

jdbcConnection = DataSourceUtils.getConnection(dataSource);

IDatabaseConnection connection = new DatabaseConnection(jdbcConnection,"TZS21911");

//以下代码用于执行前的数据库初始化

IDataSet dataSet = new FlatXmlDataSet(new FileInputStream(

"dataset.xml"));

DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);

//以下代码执行具体的测试

User user = new User();

user.setId(5);

user.setName("tzs");

user.setAge(35);

userDao.insert(user);

//以下代码用于执行后的数据库验证

IDataSet databaseDataSet = connection.createDataSet();

ITable actualTable = databaseDataSet.getTable("users");

IDataSet expectedDataSet = new FlatXmlDataSet(new File(

"expectedDatasetInsert.xml"));

ITable expectedTable = expectedDataSet.getTable("USERS");

Assertion.assertEquals(expectedTable, actualTable);

//记得要释放connection

DataSourceUtils.releaseConnection(jdbcConnection, dataSource);

}

@Override

protected String[] getConfigLocations()

{

returnnewString[] { "file:D:/workspace321/example/beans-config.xml" };

}

}

通过以上将SpringDBUnit的结合,我们既能实现用例执行前的数据库初始化以及执行后的数据库验证,也能避免用例执行中对数据库环境的影响,做到用例间数据库环境互不影响。

2 测试覆盖率检查(Cobertura

覆盖率检查工具目前在业软有使用的包括PureCoverageCoberturaPureCoverage不能与EclipseANT集成,需要单独运行,使用不太方便,而且项目组使用中经常反映有这样那样的问题,所以不推荐大家以后使用,这里我们推荐开源的Cobertura

Cobertura有两种运行方式:一方面可以与ANT集成(提供ANT任务),可以实现测试自动化;另一方面也可以单独以命令行方式运行。

Cobertura的运行步骤很简单:先对要进行覆盖率分析的CLASSJARWAR作预处理,称为instrument ,输出相同名字的文件,你要测试的是这些处理过的文件,该项操作还会生成另一个文件cobertura.ser ,用于记录类信息以及随后的覆盖率信息;然后执行单元测试, cobertura将覆盖率信息记录到cobertura.ser文件中;最后根据cobertura.ser文件输出覆盖率报告(可以是HTMLXML格式)。报告中会告诉你每个文件的覆盖比例以及未覆盖到的具体代码在哪儿,如下图。

3 自动化测试

所谓的自动化我们可以从两方面来理解,一种是在IDE(如Eclipse)下的自动化测试,我们知道JUnit集成到了Eclipse开发环境中,在Eclipse中可以边写代码边做测试,简单到只需要点击一下按钮,发现问题随时修改,并且JUnit实现了对用例的管理,引入了测试套的概念,对根测试套的一次运行能够递归运行所有的用例。

另一种是基于以下情形的自动化:有一个自动化框架,在每天的固定时间,自动从配置库上获取所有功能代码和测试代码,然后编译、做静态检查、运行所有测试用例,同时做覆盖率检查,最后输出静态检查报告、测试报告和覆盖率检查报告,并将报告打包并以Notes邮件的形式发送给相关人员。对于此种类型的自动化我们已经开发出了项目组通用的自动化测试框架,并且我们建议项目组使用该框架。

n 使用自动化测试框架的好处

1) 单元测试监控。项目组可以每天根据框架发过来的单元测试报告和覆盖率报告了解当前项目的开发和测试进展情况,所有已完成的代码是否经过了测试。

单元测试报告、覆盖率检查报告都是工具自动生成的,手工改不了,它们是单元测试做的如何的真实反映。

2) 发现合代码的问题。代码合到配置库上时,可能会发现漏合、多合、或者合错的情况,通过框架的自动测试能够及时发现这方面的问题。

3) 后期测试(指项目级系统测试以及产品级系统测试)发现问题后,可以用于验证本次问题的修改是否对系统其它部分造成影响。我们要求后期修改的问题以及新增的需求,一定要同时补充单元测试用例(测试代码),并且通过覆盖率检查报告检查源代码测试的覆盖情况。

必须指出的是,单元测试真正发现问题的过程还是每个人在IDE(如Eclipse)下的自动化测试,要确保checkin到配置库的代码是经过单元测试的,它是使用测试框架的基础。测试框架的运行只是一个结果,它的意义主要在于监控。

该自动化测试框架的主要特点就是简单,框架的核心仅是一个build.xml文件,项目组在拿到该框架后只需要对这个文件作少量修改就可以被本项目组使用,如配置项目的源代码目录、测试代码目录等,几乎不需要学习就会把这个框架用起来,并且我们还推出了相配套的例子工程,方便你更好地理解该框架。

我们要求,单元测试结束后需要提交以下报告:

静态检查报告—指自动化框架输出的静态检查报告,对不修改的BUG需要给出合理的说明。静态检查的代码范围包括所有能够编译的class文件。

单元测试报告—指自动化框架输出的单元测试报告,需要确保所有用例执行通过,对不通过的用例需要给出合理的说明。

覆盖率检查报告—指自动化框架输出的覆盖率检查报告,对没能覆盖的代码需要给出合理的说明。

另外,在项目关闭前必须重新提交一次静态检查报告、单元测试报告、覆盖率检查报告。

最后指出,该自动化测试框架不仅用于单元测试,而且一样可用于集成或系统测试的自动化,只要是基于JUnit的,因为我们知道,JUnit提供的是一个测试用例框架,不只是针对单元测试。

4 页面联调测试

最后我们谈一下页面文件的测试。我们从业软某三个项目的调查中发现,系统测试发现的缺陷有一半以上都是JSPAction问题,我们知道WEB开发涉及大量页面文件,页面文件的单元测试我们可以通过HttpUnitCactus进行验证,但它们的缺点是工作量大,而且我们的需求不稳定,所以测试成本较高,效果不好,加上页面文件技术上很难做编译检查和静态检查,同时页面文件的特点决定了做Review的效果也不理想,所以种种质量控制活动在ST都无法有效地派上用场,到STJSP中甚至还充斥了基本的语法错误。如何在编码阶段提高页面文件的质量是我们必须要解决的问题。目前我们已经在项目组推行以下试点方案:每位开发者定期(频率根据情况自定,一天或几天都可)将配置库的代码更新到本地,在本地建立运行环境(类似于系统测试环境),重点对页面文件涉及的功能进行联调,发现问题随时修改(问题无需记录),联调的用例就是系统测试用例编码阶段结束时,每位开发者都必须确保自己负责的功能相关的系统测试用例能够在本地运行通过。最终的目的是:将BUG尽量消灭在早期。

附:例子代码说明

1) example.rar

打开口令javatest,其中:

u basejunit

基本的JUnit使用。

u proxy

JAVAproxy演示,理解easymock工作原理的前提。

u easymock0

包括演示Arrays.equals,用于解释ARRAY_MATCHER参数规则、演示setDefaultReturnValuesetThrowable的使用。

u easymock1

easymock测试servlet的例子。

u easymock2

全面演示easymock使用的例子。

u easymockext

模拟类对象的例子。

u strutstest

测试struts框架的例子。

u dbunit

DBUnit测试工具演示代码。

u spring

Spring下的单元测试演示,其中包括Spring下数据库访问技术演示代码。

u build.xml

DBUnitANT的结合演示、自动化测试演示、Cobertura覆盖率检查演示。

u createtable.sql

例子代码访问的数据库表结构,在Oracle下测试通过。

u beans-config.xml

SpringXML配置文件。

u .fbprefs

FindBugs检查规则文件(版本FindBugs-1.2.1)。

2) example150.rar

是针对JUnit4.0EasyMock2.0的例子代码,打开口令javatest,其中:

u basejunit

基本的JUnit使用。

u easymock0

演示andStubReturnandThrowcreateNiceControl的使用。

u easymock1

easymock测试servlet的例子。

u easymock2

全面演示easymock使用的例子,包括自定义比较器的使用。

easymockext模拟类对象的例子。

3) framework.rar

自动化测试框架,打开口令javatest

分享到:
评论

相关推荐

    07. Spring Boot单元测试

    在Spring Boot框架中,单元测试是一项至关重要的任务,它能够帮助开发者确保代码的正确性和可靠性。Spring Boot提供了方便的工具和库,使得编写和执行单元测试变得简单高效。本章节我们将深入探讨Spring Boot中的...

    Spring3单元测试和集成测试

    在Spring框架中,单元测试和集成测试是软件开发过程中不可或缺的部分。它们确保代码的质量和功能的正确性。本文将深入探讨Spring3中的单元测试和集成测试,并提供相关的实践指导。 ### 单元测试 单元测试是指针对...

    spring单元测试包

    spring单元测试包spring单元测试包spring单元测试包spring单元测试包spring单元测试包

    spring mvc的简单单元测试

    Spring MVC 提供了对单元测试的良好支持,使得我们可以方便地测试控制器、服务层以及数据访问层。 在Spring MVC中进行单元测试,我们通常会用到以下关键技术和工具: 1. **JUnit**:JUnit是Java编程语言中最常用的...

    spring整合单元测试Junit开发包

    4. **Web应用程序测试**: Spring Test模块包含`MockMvc`类,用于模拟Spring MVC的请求和响应,可以在不运行整个服务器的情况下进行控制器的单元测试。 5. **Database测试**: 使用`@Sql`和`@SqlGroup`注解,可以执行...

    Junit4+Spring2.5单元测试代码示例(也适用注解测试)

    Junit4+Spring2.5单元测试代码示例同时也适用注解注入的形式测试(前提要导好测试的包哦,包MyEclipce自带了)

    spring mvc jpa单元测试例子

    在Spring MVC和JPA的开发过程中,单元测试是不可或缺的一部分,它可以帮助我们验证代码的正确性,确保系统各个部分能够按预期工作。本例子聚焦于使用Spring的Test注解进行事务管理的单元测试,这对于数据库操作尤其...

    Spring Boot 单元测试和集成测试实现详解

    Spring Boot 单元测试和集成测试实现详解 Springs Boot 是一个基于 Java 的框架,提供了一个便捷的方式来开发基于 Spring 的应用程序。在开发过程中,测试是一个非常重要的步骤,单元测试和集成测试是其中的两种...

    Struts+Spring框架下的单元测试

    在Struts+Spring框架下进行单元测试,主要涉及到对Action、Service以及DAO层的测试。 ### 测试Action类 在Struts框架中,Action类扮演着处理用户请求的核心角色。对于Action类的单元测试,重点在于验证Action的...

    spring+Junit4单元测试

    通过Spring集成单元测试,以后测试service层内容时,就不用getBean()来获得Service层对象了

    最简单的含单元测试的spring boot+activiti集成demo

    【标题】"最简单的含单元测试的spring boot+activiti集成demo" 描述了一种将流行的Spring Boot框架与流程管理工具Activiti结合使用的实践案例。这个集成演示项目旨在帮助开发者快速理解和实现基于Spring Boot的...

    spring MVC junit 单元测试(controller)

    在Spring MVC框架中,单元测试是确保代码质量的重要步骤,特别是在控制器层(Controller)。这篇博客主要探讨了如何使用JUnit进行Spring MVC Controller的单元测试。在实际开发中,单元测试可以帮助我们尽早发现潜在...

    Struts+Spring框架下的单元测试[总结].pdf

    总之,单元测试是保证代码质量的重要手段,在Struts+Spring的环境下,需要结合JUnit和Mockito等工具,对Action、Service和DAO进行有效的测试,确保每一层的功能都能够正确无误地工作。通过详尽的测试,可以提前发现...

    30-Spring Boot单元测试1

    Spring Boot 单元测试 Spring Boot 作为一个流行的 Java 框架,单元测试是不可或缺的一部分。单元测试的重要性不言而喻,本文将详细讲解如何在 Spring Boot 中进行单元测试。 Controller 测试 在 Spring Boot 中...

    spring单元测试

    接下来,我们关注Spring单元测试的实施。在Spring中,我们可以使用`@RunWith(SpringRunner.class)`和`@SpringBootTest`注解来启动一个完整的Spring应用上下文,以便测试Controller层。例如,对于一个名为`...

    Struts2+Spring+hibernate中对action的单元测试环境搭建[总结].pdf

    Struts2+Spring+Hibernate 中的Action单元测试环境搭建 在软件开发中,单元测试是一种非常重要的测试方法,可以帮助我们确保代码的可靠性和稳定性。在 Struts2+Spring+Hibernate 框架中,对 Action 的单元测试环境...

    Spring Boot中的单元测试.pdf

    在Spring Boot中,单元测试是确保代码质量和可维护性的重要组成部分。通过单元测试,开发者能够独立验证代码的各个部分,确保它们按照预期工作,并在修改代码后快速发现潜在问题。Spring Boot为此提供了一系列便利...

    基于Spring的JUnit单元测试

    在进行Spring单元测试时,我们还需要关注隔离性。为了确保每个测试都是独立的,避免一个测试影响另一个测试的结果,我们可以使用`@DirtiesContext`注解来标记那些可能改变上下文状态的测试方法。此外,`@Before`和`@...

    Struts2SpringUnitDemo单元测试

    Struts2SpringUnitDemo是一个示例项目,展示了如何在Java应用程序中将Struts2和Spring框架进行集成,并进行单元测试。这两个框架都是Java Web开发中的关键组件,Struts2负责控制层逻辑,Spring则提供了全面的依赖...

    spring security测试

    在这个"spring security测试"的主题中,我们将深入探讨如何对Spring Security进行单元测试,以确保我们的安全配置和逻辑正确无误。 首先,Spring Security的核心是它提供的安全拦截器(Security Interceptors),...

Global site tag (gtag.js) - Google Analytics