1、SWPUSWPU第第8章章 JUnit测试工具简介测试工具简介SWPUSWPUJUnit概述概述 1使用使用JUnit编写测试编写测试2测试的内容测试的内容 3主主要要内内容容SWPUSWPU8.1 JUnit概述概述vJUnit是一个开源的java测试框架,它是Xuint测试体系架构的一种实现。vJUnit最初由Erich Gamma 和 Kent Beck所开发。v在JUnit单元测试框架的设计时,设定了三个总体目标,第一个是简化测试的编写,这种简化包括测试框架的学习和实际测试单元的编写;第二个是使测试单元保持持久性;第三个则是可以利用既有的测试来编写相关的测试。SWPUSWPU8.2 使
2、用使用JUnit编写测试编写测试 v1、构建单元测试 测试代码必须要做的事情:准备测试所需要的各种条件(创建所有必须的对象,分配必要的资源等)调用要测试的方法 验证被测试方法的行为和期望是否一致 完成后清理各种资源(Internal Only)(Delivered)SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v1、构建单元测试 测试代码用一般的方式编写和编译 当执行测试代码的时,从来不直接运用产品代码SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v2、JUnit的各种断言 JUnit提供了一些辅助函数,用于帮助确定某个被测试函数是否工作正常。通常把所有这些函数统称
3、为断言断言。每一个断言(assert)方法都会记录是否失败了(断言为假)或有错误了(遇到一个意料外的异常)的情况,并通过JUnit的一些类来报告这些结果当一个失败或者错误出现的时候,当前测试方法的执行流程将会被中止,但是(位于同一个测试类中的)其它测试将会继续运行。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v2、JUnit的各种断言 assertEquals assertEquals(Sting message,expected,actual)相等性测试 expected是期望值(通常都是硬编码的),actual是被测试代码实际产生的值,message是一个可选的消息,如果提
4、供的话,将会在发生错误时报告这个消息。如想用断言来比较浮点数(在Java中是类型为float或者double的数),则需指定一个额外的误差参数。assertEquals(Sting message,expected,actual,tolerance)SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v2、JUnit的各种断言 assertNull assertNull(Sting message,java.lang.Object object)assertNotNull(Sting message,java.lang.Object object)验证一个给定的对象是否为null(或者
5、为非null),如果答案为否,则将会失败。Message参数是可选的。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v2、JUnit的各种断言 assertSame assertSame(Sting message,expected,actual)验证expected参数和actual参数所引用的是否为同一个对象,如果不是将会失败。Message参数是可选的 assertNotSame(Sting message,expected,actual)验证expected参数和actual参数所引用的是否为不同的对象,如相同将会失败。Message参数是可选的SWPUSWPU8.2 使
6、用使用JUnit编写测试编写测试 v2、JUnit的各种断言 assertTrue assertTrue(Sting message,Boolean condition)验证给定的二元条件是否为真,如果为假将会失败。Message参数是可选的。assertFalse(Sting message,Boolean condition)验证给定的二元条件是否为假;如果不是的话(为真),该测试将会失败,message参数是可选的。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v2、JUnit的各种断言 Fail Fail(Sting message)将会使测试立即失败,其中message
7、参数是可选的。这种断言通常被用于标记某个不应该被到达的分支SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v2、JUnit的各种断言 一般而言,一个测试方法包含有多个断言,因为需要验证该方法的多个方面以及内在的多种联系。当一个断言失败的时候,该测试方法将会被中止,从而导致该方法中余下的断言这次就无法执行了,此时只能是在继续测试之前先修复这个失败的测试。依此类推,不断地修复一个又一个的测试,沿着这条路径慢慢前进。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v3、JUnit框架 import junint.framework.*;public class Testsim
8、ple extends TestCase public TestSimple(String name)super(name);public void testAdd()assertEquals(2,1+1);public void testAdds()assertEquals(2,1+14);assertEquals(4,2+2);assertEquals(-8,-12+4);SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成 一个测试类包含一些测试方法;每个方法包含一个或者多个断言语句;测试类也能调用其它测试类:单独的类、包、甚至一个完整的系统;可以通过
9、创建test suite来取得。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成 任何测试类都能包含一个名为suite的静态方法:public static Test suite();可以提供suite()方法来返回任何想要的测试集合(没有siute()方法JUnit会自动运行所有的test方法)。但是可能需要手工添加特殊的测试,包括其它suite。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成 import junit.framework.*;public class TestClassOne extends
10、TestCase public TestClassOne(String method)super(method);public void testAddition()assertEquals(4,2+2);public void testSubtraction()assertEquals(0,2-2);SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成 import joint.framework.*;public class TestClassComposite extends TestCase public TestClassComposite(Str
11、ing method)super(method);static public Test suite()TestSuite suite=new TestSuite();/Grab everything:suite.addTestSuite(TestClassOne.class);/Use the suite method:suite.addTest(TestClassTow.suite();return suite;SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成Per-method的的Setup和和Tear-down 每个测试的运行都应该是互相独立的;从
12、而可以在任何时候,以任意的顺序运行每个单独的测试。为此,在每个测试开始之前,都需要重新设置某些测试环境,或者在测试完成之后,需要释放一些资源。JUnit的TestCase基类提供两个方法供改写,分别用于环境的建立和清理:protected void setup();protected void teardown();SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成Per-method的的Setup和和Tear-down 假设对于每个测试,都需要某种数据库连接。这时只须在setup和teardown方法中分别建立和释放连接:public class Tes
13、t DB extends TestCase private connection dbConn;protected void setup()dbConn=new Connection(“oracle”,1521,“fred”,”foobar”);dbConn.connect();protected void teardown()dbConn.disconnect();dbConn=null;public void testAccountAccess()/Uses dbConn xxx xxx xxxxxx xxx xxxxxxxxx;xx xxx xxx xxxx x xx xxxx;publ
14、ic void testEmployeeAccess()/Uses ddbConn xxx xxx xxxxxx xxx xxxxxxxxx;xxxx x x xx xxx xx xxxx;SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成Per-suite SetUp和和Tear-down 在某些情况下,须为整个test suite设置一些环境,以及在test-suite中的所有方法都执行完成后做一些清理工作。要达到这种效果,需要per-suite setup和per-suite tear-down。Per-suite 的setup要复杂些。需要提供所需
15、测试的一个suite(无论通过什么样的方法)并且把它包装进一个TestSetup对象。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成Per-suite SetUp和和Tear-down import junit.framework.*;import junit.extensions.*;public class TestClassTow extends TestCase private static TSP tsp;public TestClassTow(String method)super(method);/This one takes a few
16、 hourspublic void testLongRunner()assertEquals(2300,tsp.shortestPath(50);public void testShort Test()assertEquals(140,tsp.shortestPath(5);public void testAnotherShortTest()assertEquals(586,tsp.shortestPath(10);public static Test suite()TestSuite suite=new TestSuite();/only include short tests suite.
17、addTest(new TestClassTow(“testShortTest”);suite.addTest(new TestClassTow(“testAnotherShortTest”);TestSetup wrapper=new TestSetup(suite)protected void setUp()OoeTimeSetUp();protected void tearDown()oneTimeTearDown();return wrapper;SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v4、JUnit 测试的组成Per-suite SetUp和和Tear-down
18、 public static void onetimeSetUp()/one-time initialization code goes heretsp=new TSP();tsp.loadCities(“EasternSeaboard”);public static void oneTimeTearDown()/one-time cleanup code goes here tsp.releaseCities();SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v5、自定义Junit断言 在某些环境下,譬如要处理一个特殊的数据类型,或者处理对多个测试都共享的一系列操作,那么如果有
19、自定义的断言,将会更加方便。在测试代码中,需要把公共的测试代码抽取到方法中去,并且在测试用例中使用这些方法。考虑从TestCase继承一个类并且使用这个子类来进行所有的测试。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v5、自定义Junit断言 import junit.framework.*;/*project-wide base class for Testing*/public class ProjectTest extends TestCase /*Assert that the amount of money is an even *number of dollars
20、(no cents)*param message Text message to display if the *assertion fails *param amount Money object to test */public void assertEvenDollars(String message,Money amount)assertEquals(message,amount.asDouble()-(int)amount.asDouble(),0.0,0.001);/*Assert that the amount of money is an even *param amount
21、Money object to test */public void assertEvenDollars(Money amount)assertEvenDollars(“”,amount);SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v6、JUnit和异常JUnit框架可以捕获任何异常,并且把它报告为一个错误,这些都不需要参与。JUnit不只是让一个断言失败,而是能够跟踪整个堆栈,并且报告bug的堆栈调用顺序;当需要查找一个失败测试的原因时,这将非常有用。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v7、JUnit测试骨架 用JUnit写测试真正所需要的就三件事
22、:一个import语句引入所有junit.framework.*下的类。一个extends语句让你的类从TestCase继承。一个调用super(string)的构造函数。许多IDE至少会提供这些。这样写出来的类能够使用JUnit的test runner运行,并且自动执行类中所有test方法。SWPUSWPU8.2 使用使用JUnit编写测试编写测试 v7、JUnit测试骨架 但是有时不从JUnit的runner运行,而是能够直接运行一个测试类会更方便一些。而且每个测试运行前和后的方法名又是什么?可以制作一个骨架来提供所有这些特性并且做得相当简单。SWPUSWPU8.3 测试的内容测试的内容
23、v1、结果是否正确 v2、边界条件 v3、检查反向关联 v4、使用其他手段来实现交叉检查 v5、强制产生错误条件 v6、性能特性 SWPUSWPU8.3 测试的内容测试的内容 v1、结果是否正确 对于测试而言,首要的也是最明显的任务就是查看所期望的结果是否正确验证结果。使用数据文件使用数据文件 对于许多有大量测试数据的测试,可能会考虑用一个独立的数据文件来存储这些测试数据,然后让单元测试读取该文件。多注意一下测试数据。不管文件中的还是代码中的测试数据,都很有可能是不正确的。代码本身是否并没有测试任何异常的情况。SWPUSWPU8.3 测试的内容测试的内容 v2、边界条件 Conformance
24、 (一致性)值是否和预期的一致。Ordering(顺序性)值是否如应该的那样,是有序或者无序的。Range(区间性)值是否位于合理的最小值和最大值之内。Reference(依赖性)代码是否引用了一些不在代码范围之内的外部资源。Existence(存在性)值是否存在(例如,是否非 null,非0,在一个集合中等等)。Cardinatity(基数性)是否恰好有足够的值。Time(相对或者绝对的时间性)所有事情的发生是否是有序的?是否是在正确的时刻?是否恰好及时?SWPUSWPU8.3 测试的内容测试的内容 v3、检查反向关联 对于一些方法可以使用反向的逻辑关系来验证它们 为了检查某条记录是否成功地
25、插入了数据库,也可以通过查询这条记录来验证 注意:当同时编写了原方法和它的反向测试时,一些 bug 可能会被两个函数中都出现的错误所掩盖。在可能的情况下,应该使用不同的原理来编写反向测试。SWPUSWPU8.3 测试的内容测试的内容 v4、其他手段来实现交叉检查 计算一个量会有一种以上的算法,可使用剩下算法中的一个来交叉测试结果可以充分利用一些比较弱的版本来检查新写的超级漂亮的版本,看它们是否产生了相同的结果 使用类本身不同组成部分的数据,并且确信它们能“合起来”SWPUSWPU8.3 测试的内容测试的内容 v5、强制产生错误条件 应当能够通过强制引发错误,来测试自己的代码是如何处理所有这些真实世界中的问题的。内存耗光。磁盘用满。时钟出问题。网络不可用或者有问题。系统过载。调色板颜色数目有限。显示分辨率过高或者过低。SWPUSWPU