JUnit4通过大量引入Annotation,让我们的测试变得更加简单和高效。通过学习深入探索Junit4 的例子,进行了一些小小实践:
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
/**
* @Before:初始化方法
* @After:释放资源
* @Test:测试方法,在这里可以测试期望异常和超时时间
* @Ignore:忽略的测试方法
* @BeforeClass:针对所有测试,只执行一次,且必须为static void
* @AfterClass:针对所有测试,只执行一次,且必须为static void
* 一个JUnit 4 的单元测试用例执行顺序为:
* @BeforeClass –> @Before –> @Test –> @After –> @AfterClass
* 每一个测试方法的调用顺序为:
* @Before –> @Test –> @After
*
* @author samueli
*
*/
public class CaculatorTest {
private Caculator c = null;
private static int SUM;
@BeforeClass //设置全局静态变量,只调用一次
public static void setVar(){
for(int i = 1; i <= 10000; i++){
SUM += i;
}
}
@Before //初始化方法,每个测试方法前都会调用一次
public void init(){
c = new Caculator();
}
@After //销毁方法,每个测试方法后都会调用一次
public void destory(){
c = null;
System.gc();
}
@Test
public void sum() {
int a = 10;
int b = -10;
assertEquals(0, c.sum(a, b));
}
@Test
public void divide() {
int a = 0;
int b = -1;
assertEquals(0, c.divide(a, b));
}
@Test(expected=ArithmeticException.class) //除0抛出异常
public void exceptionDivide() {
int a = 10;
int b = 0;
c.divide(a, b);
}
@Test(timeout=1000) //耗时超过1秒测试失败
public void batchSum(){
int start = 1;
int end = 10000;
assertEquals(SUM, c.batchSum(start, end));
}
@Ignore("this test isn't working yet")
@Test
public void temp(){
int sum = 0;
for(int i = 1; i <= 10000; i++){
sum += i;
}
System.out.println(sum);
}
@AfterClass //清理全局静态变量,只调用一次
public static void clearVar(){
SUM = 0;
}
}
上面的例子完整的演示了JUnit4引入的BeforeClass,Before,Test, Ignore, After,AfterClass等注解,注释部分说明了他们的执行顺序。
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* 参数化测试
* @author samueli
*
*/
@RunWith(Parameterized.class)
public class ParametricTest {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}
// 声明两个类成员
private String phrase;
private int match;
// 匹配值的构造函数
public ParametricTest(String phrase, int match) {
this.phrase = phrase;
this.match = match;
}
/**
* 一个通用测试
* @throws Exception
*/
@Test
public void verifyGoodZipCode() throws Exception {
Matcher mtcher = pattern.matcher(phrase);
boolean isValid = mtcher.matches();
int validFlag = isValid ? 1 : 0;
assertEquals("Pattern did not validate zip code", validFlag, match);
}
/**
* 含@Parameters 注释的 feeder 方法:
* 必须声明为 static 并返回一个 Collection 类型
* @return
*/
@SuppressWarnings("unchecked")
@Parameters
public static Collection getValues() {
return Arrays.asList(new Object[][] { { "22101", 1 }, { "221x1", 0 },
{ "22101-5150", 1 }, { "221015150", 0 } });
}
}
这个参数话的例子来自原文,文中描述参数话测试的步骤摘录如下:
DW 写道
1. 创建一个不含参数的通用测试。
2. 创建一个返回 Collection 类型的 static feeder 方法,并用 @Parameter 注释加以修饰。
3. 为在步骤 1 中定义的通用方法所要求的参数类型创建类成员。
4. 创建一个持有这些参数类型的构造函数,并把这些参数类型和步骤 3 中定义的类成员相应地联系起来。
5. 通过 @RunWith 注释,指定测试用例和 Parameterized 类一起运行。
2. 创建一个返回 Collection 类型的 static feeder 方法,并用 @Parameter 注释加以修饰。
3. 为在步骤 1 中定义的通用方法所要求的参数类型创建类成员。
4. 创建一个持有这些参数类型的构造函数,并把这些参数类型和步骤 3 中定义的类成员相应地联系起来。
5. 通过 @RunWith 注释,指定测试用例和 Parameterized 类一起运行。
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/**
* 测试套件
* @author samueli
*
*/
@RunWith(Suite.class)
@SuiteClasses( { CaculatorTest.class, ParametricTest.class })
public class SuiteTest {
}
最后是我们的测试套件,指定了两个测试类。
后面附上源代码。