本文转自ITeye . 本文有改动. 如需原文连接请移步至连接 : http://bulargy.iteye.com/blog/170312
在这推荐别一篇很棒的文章 : http://www.ibm.com/developerworks/cn/education/java/j-junit4/index.html
------------------------------------------------------------------------------------------
假设我们要写一个整数除法和乘法的类,并且给他写测试用例:
1) 建立Math类
工具是eclipse3.3
- /**
- * @author bulargy.j.bai
- * @mail bulargy@gmail.com
- * @创建时间:Mar 10, 2008
- * @描述:一个整数除法和乘法的工具类
- */
- public class Math {
- public static int divide(int x,int y) {
- return x/y;
- }
- public static int multiple(int x,int y) {
- return x*y;
- }
- }
2) 建立测试用例
选中需要建立测试用例的包,选择new->other->JUnit Test Case。
有5个方法可以选择:
setUp()方法在测试方法前调用,一般用来做测试准备工作。
tearDown()方法在测试方法后调用,一般作测试的清理工作。
setUpBeforeClass()方法在整个类初始化之后调用,一般用来做测试准备工作。
tearDownAfterClass()方法在整个类结束之前调用,一般作测试的清理工作。
constructor()为是否包含构造方法。
JUnit 4 常用的几个annotation 介绍
★ @Before:初始化方法,在任何一个测试执行之前必须执行的代码;
★ @After:释放资源,在任何测试执行之后需要进行的收尾工作。在每个测试方法执行之后执行一次,该annotation只能修饰public void 方法;
★ @Test:测试方法,表明这是一个测试方法。在Junit中将会自动被执行。该annotation只你呢个修饰public void 方法。对于方法的声明也有如下要求:名字可以随便取,没有任何限制,但是返回值必须为void,而且不能有任何参数。如果违反这些规定,会在运行时抛出一个异常。至于方法内该写些什么,那就要看你需要测试些什么了;在这里可以测试期望异常和超时时间,如 @Test(timeout = 100):我们给测试函数设定一个执行时间,超过了这个时间(100毫秒),它们就会被系统强行终止,并且系统还会向你汇报该函数结束的原因是因为超时,这样你就可以发现这些Bug了。
★ @Ignore:忽略的测试方法,标注的含义就是“某些方法尚未完成,暂不参与此次测试”;这样的话测试结果就会提示你有几个测试被忽略,而不是失败。一旦你完成了相应函数,只需要把@Ignore标注删去,就可以进行正常的测试。
★ @BeforeClass:针对所有测试,只执行一次,且必须为public static void;
★ @AfterClass:针对所有测试,将会在所有测试方法执行结束后执行一次,且必须为public static void;
所以一个Junit 4 的单元测试用例执行顺序为:@BeforeClass –> @Before –> @Test –> @After –> @AfterClass;每一个测试方法的调用顺序为:@Before –> @Test –> @After。
自动生成的代码如下:
- /**
- * @author bulargy.j.bai
- * @mail bulargy@gmail.com
- * @创建时间:Mar 11, 2008
- * @描述:
- */
- public class MathTest {
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- }
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- }
- @Test
- public void testDivide() {
- fail("Not yet implemented");
- }
- @Test
- public void testMultiple() {
- fail("Not yet implemented");
- }
- }
说明:
@BeforeClass标签注释的方法用于在整个类测试过程的初始化后调用一次,@AfterClass标签注释的方法则是整个测试类结束之前调用一次。这2个标签的搭配可以避免使用@Before、@After标签组合在每个测试方法前后都调用的弊端,减少系统开销,提高系统测试速度。(不过对环境独立性要求较高的测试还是应当使用@Before、@After来完成)
@Test标签用来标注待测试的方法,按照类中声明的顺序执行。
我们在testDivide方法加入测试代码,分别测试三种情况:
a. 完全正确也没有可能出错的数据,如:9除3 结果必须等于3
b. 可能有问题的边缘数据,如:10除3 结果也必须等于3
c. 错误的数据,如:10除0 必须抛出异常
忽略testMultiple方法
代码如下:
- @Test(expected=ArithmeticException.class)
- public void testDivide() {
- assertEquals(3,Math.divide(9,3));
- assertEquals(3,Math.divide(10,3));
- Math.divide(10,0); //除数不能为0,会抛出异常
- }
- @Ignore("忽略乘法测试")
- @Test
- public void testMultiple() {
- }
说明:
Junit4为测试方法增加了判断异常的方式,避免了以前还要通过try/catch块捕捉异常再抛出的复杂方式,简单的这样声明“@Test(expected=ArithmeticException.class)”Junit4就会检查此方法是否抛出ArithmeticException异常,如果抛出则测试通过,没抛出则测试不通过(@Test标签还有一些其他参数,例如超时测试@Test(timeout=1)这样,但是由于并不能准确反应实际时间,所以应用较少,经过我测试误差太大绝对不适合拿来做超时测试的)
@Ignore标签会告诉Junit4忽略它所标注的方法,例如数据库不可用时可以用此标注标注一些测试数据库连接的方法来避免测试失败。
3) 运行测试
系统会打开JUnit透视图,如果测试全部通过,则显示颜色条为绿色;我们将assertEquals(3,Math.divide(9,3));改成assertEquals(2,Math.divide(9,3));则显示颜色条为红色,我们可以对错误或者故障的地方进行追踪。
4) 创建测试套件
测试套件可以将多个测试用例合在一起测试,将相关的测试用例合成一个测试套件,在做一个修改后,只需要运行测试套件就可以,不需要运行每一个测试用例。
Junit4没有采用以前的套件测试方法,同样使用annotation的方式来进行。简单在你所要构建测试套件的包里创建一个文件,一般以包名+4Suite
下面我在上面的测试包中复制一下之前的测试类并且一个改名字叫做MathTestAnother,新建一个class类叫做Uitl4Suite,代码如下:
- import org.junit.runner.RunWith;
- import org.junit.runners.Suite;
- import org.junit.runners.Suite.SuiteClasses;
- /**
- * @author bulargy.j.bai
- * @mail bulargy@gmail.com
- * @创建时间:Mar 11, 2008
- * @描述:util包的测试套件
- */
- @RunWith(Suite.class)
- @SuiteClasses({MathTest.class,
- MathTestAnother.class})
- public class Util4Suite {
- }
说明:
通过@RunWith和@SuiteClasses标签来注释一个空的包含无参数构造函数的类来作为套件类,将需要组成套件运行的类加到@SuiteClasses的属性中即可。
可以看到运行套件类的结果是2个测试类都进行了测试。
5) 参数测试
修改 testMultiple
- //@Ignore("忽略乘法测试")
- @Test
- public void testMultiple() {
- assertEquals(result,Math.multiple(faciend,multiplicator));
- }
编写参数方法:
- @Parameters
- public static Collection multipleValues() {
- return Arrays.asList(new Object[][] {
- {3, 2, 6 },
- {4, 3, 12 },
- {21, 5, 105 },
- {11, 22, 242 },
- {8, 9, 72 }});
- }
说明:
需要使用@Parameters标签注解一个静态的返回集合对象的方法
增加成员变量和构造函数:
- int faciend;
- int multiplicator;
- int result;
- public MathTest(int faciend, int multiplicator, int result) {
- this.faciend = faciend;
- this.multiplicator = multiplicator;
- this.result = result;
- }
最后在给测试类增加如下注释:
- @RunWith(Parameterized.class)
完整的循环测试代码如下:
- import static org.junit.Assert.*;
- import java.util.Arrays;
- import java.util.Collection;
- import org.junit.AfterClass;
- import org.junit.BeforeClass;
- import org.junit.Ignore;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.junit.runners.Parameterized;
- import org.junit.runners.Parameterized.Parameters;
- /**
- * @author bulargy.j.bai
- * @mail bulargy@gmail.com
- * @创建时间:Mar 11, 2008
- * @描述:
- */
- @RunWith(Parameterized.class)
- public class MathTest {
- int faciend;
- int multiplicator;
- int result;
- public MathTest(int faciend, int multiplicator, int result) {
- this.faciend = faciend;
- this.multiplicator = multiplicator;
- this.result = result;
- }
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- }
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- }
- @Test(expected=ArithmeticException.class)
- public void testDivide() {
- assertEquals(3,Math.divide(9,3));
- assertEquals(3,Math.divide(10,3));
- Math.divide(10,0);//除数不能为0,会抛出异常
- }
- //@Ignore("忽略乘法测试")
- @Test
- public void testMultiple() {
- assertEquals(result,Math.multiple(faciend,multiplicator));
- }
- @Parameters
- public static Collection multipleValues() {
- return Arrays.asList(new Object[][] {
- {3, 2, 6 },
- {4, 3, 12 },
- {21, 5, 105 },
- {11, 22, 242 },
- {8, 9, 72 }});
- }
- }
OK,大功告成。测试看看吧,测试类跑了5次~~。
大概就这么多体会了,总得来说JUnit4以后测试还是很方便的,顺便这个是仅仅是为了做例子,实际使用中由于JUnit4不再受命名的限制,所以应该划分更细粒度的测试来完成,一个方法的正确,异常,错误及边界数据完全可以分开来写测试方法。由于大部分情况资源只用加载和释放一次就足够,大大提高的测试的速度,再也不会有以前那样点开测试然后去泡咖啡的情况出现了~~呵呵~~