因为工作和学习的需要,在代码中查错的时候,第一步就是想知道这个错误具体发生在一个位置,进行一个准确的定位。而这个定位的工作交给谁来做了呢?不难猜出也就是这篇博客的主题---Junit。junit是一个开源的框架,也是java这一块的测试工具之一。想了解详细请上官网,下面用代码来跟大家解释。
准备要测试的方法,放进一个类中方便于测试。
package com.junit3_8; /** * junt3.8单元测试 * * @author CHH * @since 2013-01-19 * */ public class Calculator { // 加 public int add(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("加=="+sum); return a+b; } // 减 public int subtract(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("减=="+sum); return a - b; } // 乘 public int multiply(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("乘==="+sum); return a * b; } // 除 public int divide(int a, int b) throws Exception { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("除==="+sum); if (0 == b) { throw new Exception("除数不能为0"); } return a / b; } }
Junit3.8测试类
package com.junit3_8; import junit.framework.Assert; import junit.framework.TestCase; /** * * @author CHH * @since 2013-01-19 */ public class CalculatorTest extends TestCase { Calculator cal; //在“每个”测试方法执行之前被调用 public void setUp() { //这段代码在这写比较方便,只写一次就够, //不用在每个方法里写,因为这个方法每次都被调用,生成不同的对象,供测试方法使用 cal = new Calculator(); } //在“每个”测试方法执行之后被调用 public void tearDown() { } //测试方法:方法名要以test为开头,无参数,无返回类型 public void testAdd() { //Calculator cal = new Calculator(); int result = cal.add(1, 2); //第一个参数是预期的,第二个参数是真实的 Assert.assertEquals(3, result); //Assert.fail(); } public void testSubtract() { //Calculator cal = new Calculator(); int result = cal.subtract(1, 2); //第一个参数是预期的,第二个参数是真实的 Assert.assertEquals(-1, result); } public void testMultiply() { //Calculator cal = new Calculator(); int result = cal.multiply(1, 2); //第一个参数是预期的,第二个参数是真实的 Assert.assertEquals(2, result); } public void testDivide() { int result = 0; //Calculator cal = new Calculator(); try { result = cal.divide(4, 2); } catch(Exception e) { e.printStackTrace(); //让测试失败 Assert.fail(); } //第一个参数是预期的,第二个参数是真实的 Assert.assertEquals(2, result); } //除数为0的情况 public void testDivideByZero() { Throwable th = null ; //Calculator cal = new Calculator(); try { cal.divide(1, 0); Assert.fail(); } catch(Exception e) { th = e ; //e.printStackTrace(); } //th 不为空 null Assert.assertNotNull(th); //第一个参数是预期的,第二个参数是真实的 Assert.assertEquals(Exception.class, th.getClass()); Assert.assertEquals("除数不能为0", th.getMessage()); } //加了这个main方法,可以直接以 Java Application 方式运行 ,也可以以 JUnit Test 运行 public static void main(String[] args) { //命令行形式打印 junit.textui.TestRunner.run(CalculatorTest.class); //awt 界面方式显示 //junit.awtui.TestRunner.run(CalculatorTest.class); //swing 界面方式显示 //junit.swingui.TestRunner.run(CalculatorTest.class); } }
从上面的代码中可以看出Junit测试类是通过继承一个TestCase类来实现方法的测试,而这就是Junit4.0以前的测试方式,而在4.0之后他们的实现方式又有了稍微的变化。
Junit4.0之后不再是通过继承TestCase的方式来实现方法的实测,而是采用注解的方式进行的。根据Java 5.0中的新特征(注解,静态导入等),Junit开发团队也随之靠拢,采用注解的方式来进行方法的测试。这样下来相比而言JUnit 4更简单、更丰富和更易于使用。
Junit4.0测试类
package com.junit4_0;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Junit4.0
* @author CHH
* @since 2013-01-19 晚上10:12
*
*/
public class CalculatorTest {
private static Calculator calculator = new Calculator();
//每个方法测试前调用
@Before
public void clearCalculator() {
calculator.clear();
}
//每个方法测试完以后调用
@After
public void tearDown()
{
}
//@Test:测试方法,表明这是一个测试方法。在Junit中将会自动被执行。
@Test
public void add() {
calculator.add(1);
calculator.add(1);
//第一个参数是预期的,第二个参数是真实的
assertEquals(calculator.getResult(), 2);
}
@Test
public void subtract() {
calculator.add(10);
calculator.substract(2);
//第一个参数是预期的,第二个参数是真实的
assertEquals(calculator.getResult(), 8);
}
//给测试函数设定一个执行时间,超过了这个时间(400毫秒),它们就会被系统强行终止
@Test(timeout=400)
public void divide() {
calculator.add(8);
calculator.divide(2);
//第一个参数是预期的,第二个参数是真实的
assert calculator.getResult() == 5;
}
//使用注释来声明该异常是预期的,异常测试是Junit4中的最大改进
@Test(expected = ArithmeticException.class)
public void divideByZero() {
calculator.divide(0);
}
//@Ignore:忽略的测试方法,标注的含义就是“某些方法尚未完成,暂不参与此次测试”
@Ignore("not ready yet")
@Test
public void multiply() {
calculator.add(10);
calculator.multiply(10);
//第一个参数是预期的,第二个参数是真实的
assertEquals(calculator.getResult(), 100);
}
}
Junit4出了采用的注解的方式来进行测试方法之外,还增加了一些新的元素。
A、JUnit4添加了两个比较数组的assert() 方法:
public static void assertEquals(Object[] expected, Object[] actual)
public static void assertEquals(String message, Object[] expected, Object[] actual)
Junit4常用注解:
@Test 测试方法,表明这是一个测试方法。在Junit中将会自动被执行。
@Test(timeOut=400) 给测试函数设定一个执行时间,超过了这个时间(400毫秒),它们就会被系统强行终止
@Test(expected = ArithmeticException.class) 使用注释来声明该异常是预期的,异常测试是Junit4中的最大改进
@Ignore("not ready yet") 忽略的测试方法,标注的含义就是“某些方法尚未完成,暂不参与此次测试”
@Before 每个方法测试前调用
@After 每个方法测试完以后调用
@BeforeClass 每个类运行前调用,并且只调用一次
@AfterClass 每个类运行后调用,并且只调用一次
表格.@BeforeClass/@AfterClass比较于@Before/@After。
@BeforeClass和@AfterClass | @Before和@After |
在每个类中只有一个方法能被注解。 | 多个方法能被注解,但其执行的顺序未特别指定,且不运行重载方法。 |
方法名是不相关的 | 方法名是不相关的 |
每个类运行一次 | 在每个测试方法运行前或运行后运行 |
在当前类的@BeforeClass方法运行前先运行超类的@BeforeClass方法。在超类中声明的@AfterClass方法将在所有当前类的该方法运行后才运行。 | 超类中的@Before在所有子类的该方法运行前运行。在超类中的@After在在所有子类的该方法运行后才运行。 |
必须是公共和非静态的。 | 必须是公共和非静态的。 |
即使一个@BeforeClass方法抛出一个异常,所有的@AfterClass方法也保证被运行。 | 即使一个@Before或者@Test方法抛出一个异常,所有的@After方法也保证被运行。 |
总结:这两个版本最大的区别在JUnit3.x中测试必须继承 TestCase,并且每个方法名必须以test开头。比如:testMethod1()而在JUnit4.x中不必继承TestCase,采用了注解的 方式。只要在测试的方法上加上注解@Test即可,从而不必再遵循以前的一些显式约定和反射定位测试;在JUnit4.x中如果继承了TestCase, 注解就不起作用了。
并且有很重要的一点就是在JUnit4.x中继承了TestCase后,在OutLine视图中测试单个方法时,结果整个类都run 了。还有一点就是,在3.x中需要实现setUp和tearDown方法,而在4.x中无需这样,可以自定义需要在测试前和测试后的方法,在方法前加上 @before,@after就可以了。所以在JUnit4.x不必继承TestCase用注解即可对单个方法进行测试