JUnit学习文档

更新时间:2024-04-14 05:02:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

单元测试学习文档

1 什么是单元测试

单元测试——单元测试测的是独立的一个工作单元,在Java应用程序中,“独立的一个工作单元”常常指的是一个方法。

单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功

能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。例如,你可能把一个很大的值放入一个有序list 中去,然后确认该值出现在list 的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,然后确认字符串确实不再包含这些字符了。

我们所要测试的是规模很小的、非常独立的功能片断。通过对所有单独部分的行为建立起信心,确信它们都和我们的期望一致;然后,我们才能开始组装和测试整个系统。

毕竟,要是我们对手上正在写的代码的行为是否和我们的期望一致都没把握,那么其他形式的测试也都只能是浪费时间而已。在单元测试之后,你还需要其他形式的测试,有可能是更正规的测试,那一切就都要看环境的需要来决定了。

2 为什么要单元测试

单元测试不但会使你的工作完成得更轻松,而且会令你的设计变得更好,甚至大大减少你花在调试上面的时间。

2.1 可降低不确定性从而降低风险

先是在高层代码中使用了底层代码;然后这些高层代码又被更高层的代码所使用,如此往复。在对这些代码的行为没有任何信心的前提下进行下一步的开发是相当危险的,若通过单元测试,并测试通过,这就让开发者吃了一颗定心丸。

2.2 可帮助你优化设计

因为单元测试是一种白盒测试,粒度比较细,要求测试者对代码有较深层次的理解,而对代码的理解无人能比得上开发者本人,所以让开发者自己来测试时高效率的做法。

既然自己写的代码要自己测,那么开发者当然不会找麻烦地写出难以测试的代码出来,

但很巧的是,容易测试的代码基本上可以和设计良好的代码划等号,因为一个测试用例其实也就是一个单元的最早用户,容易使用显然意味着良好的设计。

3 如何进行单元测试

单元测试本来就是一项简单易学的技术;但是如果能够遵循一些指导性 原则(guideline)和基本步骤,那么学习将会变得更加容易和有效。

首先要考虑的是在编写这些测试方法之前,如何测试那些可疑的方法。 有了这样一个大概的想法之后,你将可以在编写实现代码的时候,或者之前, 编写测试代码本身。

下一步,你需要运行测试本身,或者同时运行系统模块的所有其他测试, 甚至运行整个系统的测试,前提是这些测试运行起来相对比较快。在此,我 们要确保所有的测试都能够通过,而不只是新写的测试能够通过;这一点是 非常重要的。也就是说,在保证不引入直接bug 的同时,你也要保证不会给 其他的测试带来破坏。

在这个测试过程中,我们需要确认每个测试究竟是通过了还是失败了 ——但这并不意味着你或者其他倒霉的人需要查看每个输出,然后才决定这 些代码是正确的,还是错误的。在此,你慢慢地就会养成一个习惯:只要用 眼睛瞄一下测试结果,就可以马上知道所有代码是否都是正确的,或者哪些 代码是有问题的。

4 使用JUnit进行单元测试

4.1 JUnit介绍

JUnit 是 Java? 语言事实上的 标准单元测试库。可以对一个/多个类的单个/多个方法测试,还可以将不同的 TestCase组合成TestSuit,使测试任务自动化。然而,JUnit 仅仅是一个工具而已。真正的优势来自于 JUnit 所采用的思想和技术,而不是框架本身。Eclipse同样集成了JUnit,可以非常方便地编写TestCase。

4.2 JUnit核心

当你需要写更多的test case的时候,你可以创建更多的TestCase对象,当你需要一次执行多个TestCase对象的时候,你可以创建另一个叫着TestSuite的对象,为了执行TestSuite,你需要使用TestRunner。

JUnit 的核心类:TestCase、TestSuite以及TestRunner,其中用的最多的就是TestCase,当需要多个TestCase的时候就要创建一个TestSuite,而运行TestSuite则要创建TestRunner,其关系如下:

? TestCase (测试用例) —— 扩展了JUnit的TestCase类的类。它以testXXX

方法的形式包含一个或多个测试。一个test case把具有公共行为的测试归入一组。当我们提到测试的时候,我们指的是一个testXXX方法;当我们提及test case的时候,我们指的是一个继承自TestCase的类,也就是一组测试。

? TestSuite (测试集合 )——一组测试。一个test suite是把多个相关测试

归入一组的便捷方式。例如,如果你没有为TestCase定义一个test suite,那么JUnit就会自动提供一个test suite,包含TestCase中所有的测试。

? TestRunner (测试运行器 )——执行test suite的程序。JUnit提供了几

个test runner,你可以用它们来执行你的测试。没有TestRunner接口,只有一个所有test runner都继承的BaseTestRunner。因此,当我们编写TestRunner的时候,我们实际上指的是任何继承BaseTestRunner的test runner类。

这3个类是JUnit框架的骨架,一旦你理解了TestCase,TestSuite和TestRunner

工作方式,你就可以随心所欲的编写测试了,在正常情况下,你只需要编写test

case。其他类会在幕后帮你完成测试。 此外,包括:

? TestResult(测试结果)——它包含了测试中发生的所有错误或失败。 TestResult法则收集TestCase的执行结果,报告测试结果。若测试成功,那么TestResult代码是干净的,进度条就是绿色显示,否则,TestResult就会报告失败,并输出失败测试的数目和他的stack trace。

JUnit区分失败和错误,失败是可预测的,代码中的改变不时会造成断言失败,你只是修改代码,断言就可以再次通过,但是错误(比如常规程序抛出的异常)则是测试时不可预测的,当然,错误可能意味着支持环境中的失败,而不是测试本身的失败,当遇到错误,好的分析步骤是:

? 检查环境(数据库正常运行吗?网络呢?) ? 检查测试 ? 检查代码

? Test——可以运行Test并把结果传递给TestResult。

? Assert超类型——当条件成立时,assert方法保持沉默,但条件不成立就抛出异常。

4.3 Assert

Assert超类提供了8个核心方法:

? assertTrue——断言条件为真。若不满足,方法抛出带有相应得信息(如果有的话)的

AssertionPailedError异常

? assertFalse——断言条件为假。若不满足,方法抛出带有相应得信息(如果有的话)的

AssertionPailedError异常

? assertEquals——断言两个对象相等。若不满足,方法抛出带有相应得信息(如果有的话)

的AssertionPailedError异常

? assertNotNull——断言对象不为null。若不满足,方法抛出带有相应得信息(如果有的

话)的AssertionPailedError异常

? assertNull——断言对象为null。若不满足,方法抛出带有相应得信息(如果有的话)的

AssertionPailedError异常

? assertSame——断言两个引用指向同一对象。若不满足,方法抛出带有相应得信息(如

果有的话)的AssertionPailedError异常

? assertNotSame——断言两个引用指向不同的对象。若不满足,方法抛出带有相应得信息

(如果有的话)的AssertionPailedError异常 ? fail——让测试失败。并给出指定的信息。

5 通过Eclipse建立单元测试

第一步:在eclipse中,创建一个java工程,把junit.jar包含进去:

第二步:然后写好Simple.java,如下:

package jexi.test; public class Simple {

private int n;

public Simple(int n) { this.n = n; }

// 返回绝对值: public int foo() {

return n>0 ? n : (-n); } }

该foo()方法返回绝对值,下一步,我们准备用JUnit对这个foo()方法进行全面测试。

第三步:创建测试函数

在弹出的对话框中填入测试类的名字:SimpleTest,勾上setUp():

第四步:编写测试代码:

package jexi.test;

import junit.framework.TestCase;

public class SimpleTest extends TestCase {

private Simple s1, s2;

protected void setUp() throws Exception {

super.setUp(); s1 = new Simple(10); s2 = new Simple(-7); }

public void testFoo() {

assertTrue(s1.foo()==10); assertTrue(s2.foo()==7); } }

其 中setUp()方法是构造初始化环境,我们在setUp中创建两个Simple的实例,testFoo()是用来测试foo()的测试方法,总是以 test+方法名构成,然后在测试方法中测试:s1.foo()==10,如果返回值与期待的结果10相等,assertTrue()就执行成功,

注意:JUnit推荐的做法是以test作为待测试的方法的开头,这样这些方法可以被自动找到并被测试。

第五步:我们现在可以运行Run->Run As...->JUnit Test,左侧会显示测试结果:

如果我们把Simple的foo()方法改成:

public int foo() { return n; }

再次运行JUnit Test,现在assertTrue(s2.foo()==7);测试结果就不正确了,JUnit会报告哪一行结果不正确:

双击就可以快速定位到测试失败的方法调用上。

6 SpringSide单元测试(SpringUnitTest)

Spring团队把测试当做是整个企业软件案开发必不可少的一部分。关于单元测试的具体介绍在上面已经提到,这里就讨论了采用IOC原则给单元测试带来的价值,并且主要关注与Spring框架在集成测试中带来的好处。

6.1 SpringSide框架下单元测试

采用依赖注射的一个主要好处是你的代码对容器的依赖将比传统J2EE开发小的多。无需Spring或任何其他容器,只要简单地通过 new 操作符即可实例化对象,通过这种方式组成你应用的POJO对象就可以充分利用JUnit进行测试了。你可以使用模拟对象或者其他很多有价值的测试技术将你的代码隔离起来进行测试。如果你的应用在架构上遵循了Spring的建议,那么你的代码将会有清晰的层次和高度的模块化,这些都将大大方便单元测试。例如,在单元测试中你可以通过测试框架或者模拟DAO接口的方式来测试服务层对象而无需访问持久化数据。

真正的单元测试运行起来通常都非常迅速,因为没有应用服务器,数据库,ORM工具等运行设施需要设置。因此加强正确的单元测试可以大大提高你的生

产力。所以并不需要本节来帮助你为你那些基于IoC的应用编写有效的单元测试。

6.2 需要Spring依赖注入的测试

为了测试Spring管理下的Bean,可以自行构造BeanFactory,也可以继承于AbstractDependencyInjectionSpringContextTests,实现public String[] getConfigLocations()函数, 返回applicationContext文件路径的数组。 protected String[] getConfigLocations() {

return new String[]{\\ }

并显式写一些需要注入的变量的setter函数。

tips1:此基类有一个applicationContext的成员变量,所以除了依靠setter注入外,还可以随时用applicationContext.getBean(String beanName) 取出所需的bean。

tips2:注意此基类默认是autowire by type的,所以如果context文件里有两个相同类型的Bean就会报错,可能需要在getConfigLocations()函数里, setAutowireMode(AUTOWIRE_BY_NAME);把它设回by name,或者取消setter函数,自行用applicationContext.getBean()来显式查找Bean。

6.3 Dao测试

AbstractTransactionalDataSourceSpringContextTests 继承于

AbstractDependencyInjectionSpringContextTests,除了拥有上类的能力外,还管理了每个测试的事务,会Open Session In Test,还会在每个测试后默认回滚所有的操作。

深此类的实现其实依赖于Application Context中定义的 PlatformTransactionManager。由于使用了Autowrie by type,PlatformTransactionManager可以任意取名。

另外还依赖于Application Context中定义的DataSource,同样可以任意取名。

tips1:如果需要在测试后提交,需要setRollBack(false); 或者调用setComplete(); 注意如果没有提交,hibernate这样奸诈的Framework就不会去实际操作数据库,降低了测试的效果。

tips2:此基类还通过注入的DataSource创建了一个JDBCTemplate 变量,可以跑SQL帮忙核对Hibernate的结果,Spring将确保该查询在同一个事务内执行。为正常工作你需要告诉你的ORM工具'刷新'它的已 改变内容,例如使用Hibernate Session 接口的 flush() 方法。

tips3:除了tips2以外,该类还有countRowsInTable(String tableName),deleteFromTables (String[] names) ,

executeSqlScript(String sqlResourcePath, boolean continueOnError)三个简便函数。

Dao测试基类,继承于

AbstractTransactionalDataSourceSpringContextTests. 该类带OpenSessionInTest与事务默认回滚能力,并带有一jdbcTemplate变量可在同一事务内检查数据库变化.实现了基类的getConfigLocations()函数,设置默认的applicationContext, 在子类可重载此函数以减少载入的applicaitonContext.mxl,加快测试速度.

设置AUTOWIRE_BY_NAME ,因为Spring的测试基类默认为BY_TYPE,在有多个相同类型的Bean时冲突.

6.4 基类测试

Spring环境下的测试基类,继承于

AbstractTransactionalDataSourceSpringContextTests.用于测试Struts2的Web Action。

该类带Spring的IOC能力,子类只要设置Setter即可获得依赖注入.实现了基类的getConfigLocations()函数,设置默认的applicationContext,在子类可重载该函数,减少载文件,加快速度.

设置AUTOWIRE_BY_NAME ,因为Spring的测试基类默认为BY_TYPE,在有

多个相同类型的Bean时冲突.

6.5 Selenium自动测试(功能测试)

SpringSide2.0 已经全面应用Selenium。Selenium集成测试基类.负责启动和关闭

selenium服务。 Selenium是一个用于Web应用程序测试的工具。Selenium 测试直接

运行在浏览器中,就像真正的用户在操作一样。

6.5.1 前言

Selenium能被选为最好集成测试、回归测试方案的原因是:

1. Selenium IDE ,一个FireFox plugin,能自动记录用户的操作,生成测试脚本。 2. 生成的测试脚本可以用Selenium Core手工执行,也能基于Selenium RC放入Java,C#,Ruby的单元测试用例中自动运行。 3. 测试用例调用实际的浏览器(如IE、FireFox)来执行测试。和有些开源方案自行实现Web解释引擎相比,实际的浏览器能模拟更多用户交互和JS语法,顺便还可以测试各浏览器兼容性。

4. 测试脚本语法非常简单,见后。

6.5.2 使用Selenium IDE生成脚本

Selenium IDE是一个Firefox插件,下载后用Firefox将其打开。(建议此处FireFox用2.0版本)

工具->Selenium IDE,点击红色的recorder按钮开始录制,在网站中乱点时可以即时看到每个动作的脚本。

切换Format:显示 HTML,Java,C#,Ruby 语法的脚本。 option里还可以设定Java里Selenium变量的名称,如设为user,使脚本显示为user.input(%user.type(\,阅读比较自然。具体步骤如下:

6.5.2.1 打开Firefox,浏览网页:

6.5.2.2 录入脚本准备

打开Selenium IDE

选择脚本句法为Java

配置java语法的参数为user

6.5.2.3 生成脚本

具体操作如下:

添加一条记录->修改该记录->删除另一条记录 下面是以上操作的具体脚本代码

6.5.2.4 测试准备

修改\\helloworld\\test\\functional\\com\\sinosoft\\helloworld\%user\\functional\\UserActionFunTest.java文件

具体代码如下: public void setUp() { // super.setUp(); user = new DefaultSelenium(\ \ user.start(); user.open(\ user.waitForPageToLoad(DEFAULT_TIME); } public void testNew() throws Exception { user.open(\ user.click(\ user.waitForPageToLoad(\ user.type(\ user.type(\ user.type(\ user.click(\ user.waitForPageToLoad(\ user.click(\ user.type(\ user.click(\ user.waitForPageToLoad(\

}

红色为新增加的代码,蓝色为注释掉的代码。此处的新增函数testNew()就是刚刚通过Selenium IDE自动生成的脚本代码

说明:如果想默认为FireFox浏览器测试,则修改*iexplore为*firefox;

6.5.2.5 开始测试:

下图为\\helloworld\\bin目录结构:

首先双击startSeleniumServer.bat批处理文件启动SeleniumServer,下图为控制台信息:

然后双击fun-test.bat文件开始测试:

自动启动浏览器开始执行脚本:

seleniumServer控制台将出现如下信息:

fun-test控制台:

脚本执行完毕没有出现错误,说明测试成功 否则可以按提示去相应目录下查看错误报告。

本文来源:https://www.bwwdw.com/article/9knp.html

Top