JNuit4实战技巧总结
众所周知,JUnit在java言阵营中测试框架普及率始终居于领先的位置,甚至可以说是最受欢迎的基础测试框架。随着JUnit4的推出,更是大大简化了广大测试人员在编写日常基础测试api的工作量。JUnit4放弃了过去严格的命名规范和继承层次,转而推崇java 5注释的灵活性借助Java 5注释,JUnit4比以前更轻、也更更灵活,下面是一份关于JUnit4新功能的快速列表:
- 参数测试
- 异常测试
- 超时测试
- 灵活固件
- 忽略测试的简单方法
- 对测试进行逻辑分组的新方法
应该说JUnit4里添加了许多新功能,但是在本篇博文里,我们仅从最实用的技巧中来快速学习JUnit4测试框架的使用。首先让我们来快速了解下JUnit4中最常用的六个注释的介绍:
- @Before:初始化方法
- @After:释放资源
- @Test:测试方法,在这里可以测试期望异常和超时时间
- @Ignore:忽略的测试方法
- @BeforeClass:针对所有测试,只执行一次,且必须为static void
- @AfterClass:针对所有测试,只执行一次,且必须为static void
在一个JUnit4的单元测试用例中被上述注释所注释的api执行顺序为:@BeforeClass->@Before->@Test->@After->@AfterClass,而在每个测试方法中的调用顺序为:@Before->@Test->@After,以上两个执行顺序中之所以没有出现@Ignore注释,那是因为此注释表明不会在测试用例中执行被此注释的api,当然也就无所谓执行顺序呢。普及了这么多的理论知识,接下来,还是让我们用实例代码来说明吧,实践出真知嘛!
首先贴出demo代码吧:
1: import static org.junit.Assert.*;2: import org.hibernate.Query;3: import org.hibernate.Session;4: import org.hibernate.SessionFactory;5: import org.hibernate.Transaction;6: import org.hibernate.cfg.Configuration;7: import org.junit.After;8: import org.junit.AfterClass;9: import org.junit.Assert;10: import org.junit.Before;11: import org.junit.BeforeClass;12: import org.junit.Ignore;13: import org.junit.Test;14:
15: import java.util.ArrayList;16: import com.paas.model.user.User;17:
18: public class JNuitDemo {19: private static Configuration configuration;20: private static SessionFactory sf;21: private static Session session;22: private static Transaction tx;23:
24: private int foo;25:
26: @BeforeClass27: public static void init(){28: configuration=new Configuration().configure();29: sf=configuration.buildSessionFactory();30: session=sf.openSession();31: tx=session.beginTransaction();32: }
33:
34: @AfterClass35: public static void destroy(){36: if(session.isOpen())37: session.close();38: if(!sf.isClosed())39: sf.close();40: configuration=null;41: }
42:
43: @Before44: public void initFoo(){45: foo=100;46: }
47:
48: @After49: public void destroyFoo(){50: foo=0;51: }
52:
53: @Test54: public void testGetAllUsers(){55: tx.begin();56: Query query=session.createQuery("from User where username!= ? and password!=?");57: query.setString(0, "admin");58: query.setString(1, "admin");59: ArrayList<User> users=(ArrayList<User>)query.list();
60: tx.commit();61: Assert.assertEquals(3, users.size());
62: }
63:
64: @Test65: public void testFoo(){66: Assert.assertEquals(100, foo);67: }
68:
69: @Ignore70: public void testFoo4Ignore(){71: Assert.assertEquals(1, foo);72: }
73:
74: }
上面测试测试运行的结果为:
接下来就让我们全面分析一下上述代码和测试结果吧!
在上述示例代码中,我们使用到了前方说到的所有六个注释。为了便于从实战的角度来说明JUnit4框架的使用技巧,我们使用了hibernate框架。若需要使用hibernate框架,则我们首先必须初始化hibernate框架,也就是通过读取相关配置文件(hibernate.cfg.xml)来实例化configuration对象,继而获得session对象,这样我们就可以用session来进行数据的持久化操作呢。像这样初始化资源的步骤,在设计测试用例时,我们通过将其置于被@BeforeClass或者@Before注释的api中,因为被@BeforeClass或者@Before注释过的api,会优先于被@Test注释的真正用来进行测试的api执行,上文已经对各个注释的执行先后顺序做了说明。在我们的示例代码中,我们使用了@BeforeClass注释来注释init()方法,在此方法中完成资源的初始化过程,方便之后真正测试方法中对该资源的需求(在这里主要是session)。不过,我们也注意到,被@BeforeClass注释的api类型被标注为static类型,这是JUnit框架所要求的,那么这也就意味着在init()方法里用到的测试类的成员变量类型必须也为static类型,否则不符合java语法要求。这一点,需要大家稍微注意些。当然,在这里,我们也可以使用@Before注释来注释init()方法,惟一不同的是,被@Before注释的api不需要被标注为static类型,与普通成员函数完全一样。因此,在日常编写测试用例时,到底选择哪一个注释来完成资源的初始化,则要视实际情况和个人喜好呢。既然有资源被初始化,至少也就少不了在测试完结时回收资源的动作,我们可以通过@AfterClass或者@After来标注完成资源回收的api,比如示例代码中的destroy()方法,自然,被@AfterClass或者@After标注的api会是最后运行的api,也就是最后的资源回收的动作,与@BeforeClass相同,api也必须被标注为static类型。同理,在这里,我们也完全可以使用@After来标注destroy()方法。与@Before一样,被@After标注的api要求与普通类成员api完全一样。
下面,我们来谈谈另外两个注释:@Test和@Ignore。其中@Test注释用来指明真正执行测试的api,也就是说,在执行完@BeforeClass或者 @Before注释的api之后,接下来就是执行被@Test注释的测试api。其中,针对@Test注释来说,我们常用的使用技巧就是超时测试,使用上也比较简单,通过在@Test中添加超时时限即可,即@Test(timeout=1000),这表明,如果在运行该测试api超过一千毫秒时,则测试失败,不管结果是否正确。而@Ignore的作用与@Test恰好相反,通过@Ignore指明当前测试api不参与当前测试用例的测试过程,也就是不会被执行,不管结果正确与否。从上述可知,在我们编写自己的测试用例时,我们可以通过注释@Test和@Ignore灵活、方便地来控制测试api参与测试运行与否。大大节省了我们编写测试用例的时间,我们不得不感谢java 5注释带给我们程序员更高效的编程效率。
接下来,我们谈谈用于完成对测试结果进行判断的Assert类吧。在这里,我简称为Assert为断言类,此类中所包含的api均为static类型,我们可以通过类名方便地引用相应的断言api,比如在示例代码中,我们就使用了Assert.assertEquals(expected, actual),当actual值与expected值相等时,则测试通过,否则测试失败。下面,通过截图来看看Assert类究竟提供了多少断言api吧!
从上面的截图里,我们可以看到,Assert类确定提供了很全面的断言api,有简单类型的相等判断类断言api,亦有复杂类型的相等判断类断言api,比如数组类型的相等判断等。至于各个断言api的使用方法,相信在查看api原型后就一目了然呢。因此,各个断言api的使用方法,就不在此赘述呢。
通过上述对文章开头提到的六个基本注释的讲解和使用,相信大家对使用JUnit4进行基本的测试用例的编写应该不会再感到陌生呢。但是,千万不要以为JUnit就仅仅只能为我们做这样一些工作。接下来,我们再来介绍些更高级的测试技巧吧!之前, 我们都是针对测试用例来编写相关的测试方法,现在我们引入测试套件的概念。所谓测试套件,就是包括多个测试用例的集合体,可以同时运行多个测试用例,这样我们也就可以通过测试套件来完成我们测试用例的逻辑分类,将同类的测试用例逻辑上归为一类,并同时运行所有的测试用例,这样是不是又比前文中所述的测试用例更近一步呢。首先,我们来看看使用JUnit4如何来编写测试套件吧!
1: import org.junit.runner.RunWith;2: import org.junit.runners.Suite;3: import org.junit.runners.Suite.SuiteClasses;4:
5: @RunWith(Suite.class)6: @SuiteClasses({JNuitDemo.class,JNuitDemo2.class})7: public class Demo4Suite {8:
9: }
测试结果如下:
从上述示例代码中,我们可以看到,编写测试套件是如此简单的一件事,一方面,只要在类的上方添加@RunWith(Suite.class)注释,其中Suite.class为JUnit4默认的运行器,在些运行器中运行所有需要运行的测试用例,另一方面则只需要再添加@SuiteClasses({JNuitDemo.class,JNuitDemo2.class})注释,指明需要一起运行的所有测试用例的class,逻辑上我们将上述JNuitDemo.class,JNuitDemo2.class归为一类,这样我们就可以实现真正意义上将测试逻辑分类呢。从测试结果上来看,两个测试用例的所有被@Test标注的测试api都已经成功运行呢,这正是我们想要达到的效果,不是吗?很简单吧,赶紧动手试试吧!
到这里,我们差不多已经将基本常用的JUnit4测试方法都已经讲解完呢,至于一些不常用的JUnit测试技巧,在这里就不多多介绍呢。相信入门后,再掌握更“高级”的测试技巧相信对聪明的你也不会是一件多难的事,对吧?
作为结束语,我们来说说JUnit4吧!JUnit 4 显著地背离了以往的设计并不意味着该框架执行起来和以往完全不同 —— 原有框架的强大功能和简洁性仍完好无损。事实上,如果深入发掘该框架,我们会发现,尽管添加了一些强制性的新功能,但新框架并未牺牲任何曾引发开发人员测试革命的核心原则。一件事是希望大家明白的,那就是:注释并没有削弱 JUnit 的功能,相反,它们的确带来了相当可观的易用性。通过使用注释会让我们在不知不觉中就能来去自如地驾驭测试的编写!谢谢大家!
最后附上在myeclipse进行JUnit测试开发的图示说明:
1、需要手工加入JUnit4核心Jar包。
2、在编写完测试用例后,点击右键,选择Run as –> JUnit Test即可。
3、如何调出可视化JUnit界面,查看测试结果,方法如下:
选择“Other”,然后输入JUnit,再选择JUnit
点击“OK”即可!