JUnit是Java的单元测试框架。JUnit提倡“先测试后编码”的理念,强调建立测试数据的代码,可以先测试,再应用。
框架的特点:
JUnit是开放的资源框架,用于编写和运行测试; 提供注释来识别测试的方法;
提供断言来测试预期结果;
提供测试运行来运行测试;
单元测试用例的特点: 预期输入和预期输出。预期输入需要有测试的前置条件,预期输出需要有测试的后置条件;
每一项需求至少需要两个单元测试用例:一个正向验证(是否做了该做的事),一个负向验证(是否做了不该做的事)。 若一个需求有子需求,每一个子需求必须至少有正向验证和负向验证两个测试用例。负向用例可以有多个;
API: 官网API地址:http://junit.org/junit4/javadoc/latest/index.html 核心包junit.framework和junit.runner。Framework包-->整个测试对象的构架,Runner-->测试驱动;
JUnit的四个核心类:TestCase、TestSuite、TestRunner、TestResult;
TestResult: 测试结果。收集TestCase所执行的结果,将结果分为两类,可预测的Failure和没有预测的Error。同时将测试结果 转发到TestListener(该接口由TestRunner继承)处理;
TestRunner: 测试运行器。对象调用的起始点,对整个测试流程的跟踪。能显示返回的测试结果,并且报告测试的进度;
TestSuite: 测试集合。包装和运行所有的TestCase;
TestCase: 测试用例。测试类所要继承的类,测试时对被测试类进行初始化,及测试方法调用;
重要的接口:Test和TestListener Test的主要方法:run()和countTestCases();
TestListener的主要方法:addError()、addFailure()、startTest()和endTest();
基本的测试过程: TestClass.class(被测试类)-->TestCase(测试用例)-->TestSuite(测试用例集合)-->TestRunner(测试运行器)-->TestResult(测试结果)
例子:
public class Message { //被测试类
private String message = null;
public boolean isPrint = false;
public Message(String message) {
this.message = message;
}
public String printMessage() { // method1-->case1
System.out.println(message);
this.isPrint = true;
System.out.println(this.isPrint + "...");
return this.message;
}
public String changeMessage(String str) { // method2-->case2
this.message += str;
return this.message;
}
public String handleMessage(String str){ // method3-->case3
int a = str.length();
if(a>=5){
this.message = str.substring(0, 5);
}
return this.message;
}
}
public class MessageTestCase1 { //测试用例1
String info = "new String";
Message m = new Message(info);
@Test
public void test1() {
m.printMessage();
assertEquals(true, m.isPrint);
}
@Test
public void test2() {
m.printMessage();
assertEquals(false, m.isPrint);
}
}
public class MessageTestCase2 { //测试用例2
String s = "aa";
Message m = new Message(s);
@Test
public void test1(){
String str = "aazz";
assertEquals(str,m.changeMessage("zz"));
}
@Test
public void test2(){
String str = "asdf";
assertEquals(str,m.changeMessage(str));
}
}
public class MessageTestCase3 { //测试用例3
String str = "abcdefgh";
Message m = new Message("a");
@Test
public void test1(){
assertEquals(5,m.handleMessage(str).length());
}
@Test
public void test2(){
assertEquals(4,m.handleMessage(str).length());
}
@Test
public void test3(){
assertEquals(6,m.handleMessage(str).length());
}
}
@RunWith(Suite.class)
@Suite.SuiteClasses({ MessageTestCase1.class, MessageTestCase2.class,
MessageTestCase3.class })
public class MessageTestSuite { //测试用例集
//public static void main(String[] args) {
//
//TestSuite suite = new TestSuite(MessageTestCase1.class,
//MessageTestCase2.class,MessageTestCase3.class);
//
//TestResult result = new TestResult();
//suite.run(result);
//
//}
}
public class MessageTestRunner { //测试执行器
public static void main(String[] args) {
Result result = JUnitCore.runClasses(MessageTestSuite.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
System.out.println("TestResult:" + result.wasSuccessful());
}
}
Ignoring Tests 含有@Ignore注释的测试方法将不会被执行;
用@Ignore注释的测试类,它的测试方法将不会执行;
例子:
@Ignore("冗余测试用例")
@Test
public void test3(){
assertEquals(6,m.handleMessage(str).length());
}
Timeout for Tests
设置超时时间,对用例执行时间进行控制。 第一种用法:
@Test(timeout=10000)
public void test2(){
assertEquals(4,m.handleMessage(str).length());
}
第二种用法(设置超时规则。写在测试类中,测试类中的所有测试方法均遵守此规则):
@Rule
public Timeout globalTimeout = Timeout.seconds(10);
Exception Testing
测试代码是否抛出预想的异常。 例子:
Class.forName("jdbc.mysql.Driver");
@Test(expected = ClassNotFoundException.class)
public void test1() {
Class.forName("jdbc.mysql.Driver");
}
Parameterized Tests
参数化测试允许使用不同的值反复运行同一个测试。可以按照以下步骤来创建参数化测试:
用 @RunWith(Parameterized.class) 来注释 test 类; 创建一个由 @Parameters 注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合; 创建一个公共的构造函数,它接受和一行测试数据相等同的东西; 为每一列测试数据创建一个实例变量;
用实例变量作为测试数据的来源来创建你的测试用例;
例子:
public class Test123 { //被测试类
private Integer a;
private Integer b;
public int add(int a, int b) { //
return a + b;
}
}
@RunWith(Parameterized.class)
public class TestCase { //使用参数化的 测试用例
private Integer input1;
private Integer input2;
private Integer result;
public TestCase(Integer a, Integer b, Integer c) {
this.input1 = a;
this.input2 = b;
this.result = c;
}
@Parameters
public static Collection addNumbers() {
return Arrays.asList(new Object[][] { { 1, 2, 3 }, { -6, -3, -9 },
{ 1, -6, -5 }, { 2, 0, 6 }, { 99, 9, 108 } });
}
@Test
public void test1() {
Test123 t =new Test123();
assertEquals(result.intValue(), t.add(input1, input2));
}
}
Rules
@ClassRule
public static Service service = Service.getInstance(); //必须是静态的
@Rule
public Service tmp = service;
@ClassRule:set up the external resource in your example. @Rule:resetting the resource in that example.
参考: http://wiki.jikexueyuan.com/project/junit/ http://junit.org/junit4/ http://*.com/questions/20767486/combining-classrule-and-rule-in-junit-4-11
注: