1. 程式人生 > >JUnit學習筆記(一):基本用法

JUnit學習筆記(一):基本用法

JUnit學習筆記(一):基本用法 JUnit是Java的單元測試框架。JUnit提倡“先測試後編碼”的理念,強調建立測試資料的程式碼,可以先測試,再應用。
框架的特點
    JUnit是
開放的資源框架,用於編寫和執行測試;
    提供註釋來識別測試的方法;
    提供斷言來測試預期結果;
    提供測試執行來執行測試;

單元測試用例的特點
    預期輸入和預期輸出。預期輸入需要有測試的前置條件,預期輸出需要有測試的後置條件;
    每一項需求至少需要兩個單元測試用例:一個正向驗證(是否做了該做的事),一個負向驗證(是否做了不該做的事)。
    若一個需求有子需求,每一個子需求必須至少有
正向驗證和負向驗證兩個測試用例。負向用例可以有多個;
API     官網API地址:http://junit.org/junit4/javadoc/latest/index.html     核心包junit.frameworkjunit.runner。Framework包-->整個測試物件的構架,Runner-->測試驅動;
    JUnit的四個核心類:TestCaseTestSuiteTestRunnerTestResult 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://stackoverflow.com/questions/20767486/combining-classrule-and-rule-in-junit-4-11
注: