軟件測(cè)試
___________________________________________________________________________
Unit Test是由程序員本身來(lái)編寫(xiě)的。
以下介紹Junit單元測(cè)試框架:官網(wǎng)地址www.junit.org
JUnit是由 Erich Gamma 和 Kent Beck 編寫(xiě)的一個(gè)回歸測(cè)試框架(regression testing framework)。Junit測(cè)試是程序員測(cè)試,即所謂白盒測(cè)試,因?yàn)槌绦騿T知道被測(cè)試的軟件如何(How)完成功能和完成什么樣(What)的功能。
Junit3.x
___________________________________________________________________________
Junit3.x中使用包junit.framework.*
1. 必須繼承TestCase類
public class CalculatorTest extends TestCase {
private Calculator cal;
public CalculatorTest() {
}
public CalculatorTest(String name) {
super(name);
}
public void setUp() {
System.out.println("...........setUp..............");
cal = new Calculator();
}
public void testAdd() {
int result = cal.add(1, 2);
Assert.assertEquals("計(jì)算添加失敗", 3, result);
}
public void tearDown() {
System.out.println("........tearDown........");
}
}
2. 測(cè)試用例(Test Case)是單元測(cè)試的一個(gè)非常重要的方面。
3. 單元測(cè)試主要是用來(lái)判斷程序的執(zhí)行結(jié)果與自己期望的結(jié)果是否一致。
4. 在Junit3.x中,測(cè)試方法規(guī)則定義如下:
1) public
2) void
3) 無(wú)參數(shù)的
4) 測(cè)試方法名以test開(kāi)頭
5. Test Case之間一定要保持完全的獨(dú)立性,不允許出現(xiàn)任何的依賴關(guān)系。
6. 我們不能依賴于測(cè)試方法的執(zhí)行順序。
7. 關(guān)于setUp與tearDown方法的執(zhí)行順序:
1) setUp
2) testAdd
3) tearDown
8. Junit兩種類型錯(cuò)誤,F(xiàn)ailure 和 Error
Failure:指預(yù)期結(jié)果與實(shí)際結(jié)果不同,例如當(dāng)你使用assertEquals或者assertXXX方法斷言失敗時(shí),或者調(diào)用fail方法,就會(huì)報(bào)出Failure,這時(shí)要檢查測(cè)試方法邏輯設(shè)計(jì)是否有誤。
public void testDevide() {
System.out.println(".........testDevide()........");
int expected = 0;
int actual = 0;
try {
actual = cal.devide(1, 3);
} catch (Exception e) {
Assert.fail("測(cè)試失敗"); //不應(yīng)該執(zhí)行這段.
}
Assert.assertEquals(expected, actual);
}
Error:指程序在斷言執(zhí)行之前,程序就因?yàn)槟撤N錯(cuò)誤而引發(fā)異常,導(dǎo)致程序終止,例如測(cè)試方法中因拋出某個(gè)異常,使得測(cè)試方法無(wú)法正確執(zhí)行到斷言就結(jié)束,這時(shí)你要檢查測(cè)試的方法是否有未考慮到的情況而引起流程突然中斷。
也就是說(shuō)代碼中拋出了異常等影響代碼正常執(zhí)行的情況,比如ArrayIndexOfBoundsException、NullPointException,也可能是磁盤(pán)已滿、網(wǎng)絡(luò)中斷等等外部環(huán)境失敗所帶來(lái)的影響。
首先處理Error,然后在處理Failure.
9. 運(yùn)行測(cè)試用例
1) IDE中,如Eclipse工具已經(jīng)內(nèi)置了Junit,所以可以直接在測(cè)試類中鼠標(biāo)右鍵Run--Junit Test運(yùn)行。
2) 使用junit.textui.TestRunner類運(yùn)行測(cè)試類.
public static void main(String[] args) {
junit.textui.TestRunner.run(MyStackTest.class);
junit.textui.TestRunner.run(new CalculatorTest("testAdd"));
}
3) 使用TestSuite
a) 一次可以運(yùn)行多個(gè)測(cè)試類進(jìn)行測(cè)試
public class TestAll {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(OOOTest.class);
suite.addTestSuite(XXXTest.class);
suite.addTestSuite(YYYTest.class);
return suite;
}
public static void main(String[] args) {
TestRunner.run(suite());
}
}
b) 通過(guò)IDE自動(dòng)發(fā)現(xiàn)suite()方法,必須繼承TestCase
public class TestAll extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(OOOTest.class);
suite.addTestSuite(XXXTest.class);
suite.addTestSuite(YYYTest.class);
return suite;
}
}
c) 組合模式,組合方式多元化
……
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new XXXTest("testABC")); // 執(zhí)行testABC()方法
suite.addTest(YYYTest.suite()); // suite() 傳回TestSuite實(shí)例
suite.addTestSuite(OOOTest.class);//自動(dòng)查找OOOTest類中testXXX方法
return suite;
}
10.測(cè)試之前是什么狀態(tài),在測(cè)試執(zhí)行完成后就應(yīng)該是什么狀態(tài),而不應(yīng)該由于測(cè)試執(zhí)行的原因到導(dǎo)致了狀態(tài)發(fā)生了變化。
Junit4.x
___________________________________________________________________________
Junit4.x開(kāi)始支持Annotation注解技術(shù),在編寫(xiě)測(cè)試用例時(shí)簡(jiǎn)化不少動(dòng)作.
Junit4.x中使用的包org.junit.*
Junit4.x是兼容以前版本
Eclipse中自帶了Junit4,版本為junit4.3.1. BC-EC工程中使用的版本為Junit4.4,目前最新版本4.11
1. 無(wú)需繼承TestCase類,所有被@Test注解所修飾的public,void,無(wú)參數(shù)的方法都是測(cè)試用例,Junit自動(dòng)查找注解方法并執(zhí)行測(cè)試。
@Test
public void testAdd() {
int result = cal.add(1, 2);
Assert.assertEquals("計(jì)算添加失敗", 3, result);
}
2. 雖然Junit4.x中測(cè)試類中的方法名稱可以隨便取,但是建議跟junit3.x中測(cè)試類方法命名約定一致,統(tǒng)一方法名以test開(kāi)頭。
3. 使用@Before注解所修飾的方法同junit3.x中的setUp方法的功能,使用@After注解所修改的方法同junit3.x測(cè)試類中的tearDown方法的功能。 @Before和@After可以在多次指定.
@Before
public void init() {
System.out.println("...........setUp..............");
cal = new Calculator();
}
@After
public void destroy() {
System.out.println("........tearDown........");
}
4. 通過(guò)@BeforeClass和@AfterClass注解標(biāo)注public,static,void,無(wú)參數(shù)的類方法。在所有測(cè)試方法執(zhí)行之前和之后執(zhí)行。
@BeforeClass
public static void setUpBeforeClass() {
...
}
@AfterClass
public static void tearDownAfterClass() {
...
}
5. 使用@Ignore注解所修飾的方法(可以表示尚未編寫(xiě)完該用例或者想禁用該用例),運(yùn)行器會(huì)忽略該方法的測(cè)試;當(dāng)修飾類時(shí),運(yùn)行器會(huì)忽略掉所有測(cè)試方法。
@Test
@Ignore("尚未完成")
public void testMultiply() {
… …
}
Eclipse中Junit執(zhí)行結(jié)果中會(huì)提示如下:
6. 預(yù)期異常:
也可以使用在junit3.x中提到的fail()來(lái)測(cè)試預(yù)期拋出異常的情況。
public void testDevideByZero() {
Throwable tx = null;
try {
cal.devide(1, 0);
Assert.fail("應(yīng)該按預(yù)期拋出異常,測(cè)試失敗");
} catch (Exception e) {
tx = e;
}
Assert.assertNotNull(tx.getMessage());
Assert.assertEquals(ArithmeticException.class, tx.getClass());
Assert.assertEquals("除數(shù)不能為0!", tx.getMessage());
}
junit4中使用Test中的expected屬性達(dá)到相同的功能,代碼量小很多.
@Test(expected = ArithmeticException.class)
public void testDevideByZero() throws Exception {
cal.devide(1, 0); // 應(yīng)該拋出異常
}
7. 使用@Test(timeout = 2000) 注解預(yù)期某些操作應(yīng)該在指定時(shí)間內(nèi)完成,否則測(cè)試失敗。 單位是毫秒。
8. 測(cè)試運(yùn)行器:可以使用@RunWith注解使用的runner.
Junit4中內(nèi)置的運(yùn)行器有:
a) 附帶兼容junit3.x運(yùn)行器
org.junit.internal.runners.Junit38ClassRunner
b) 參數(shù)化運(yùn)行器,可設(shè)定一組參數(shù),每次運(yùn)行測(cè)試時(shí)自動(dòng)在指定位置給予不同的參數(shù)。
org.junit.runners.Parameterized
c) Suite運(yùn)行器,如同Junit3.x中的TestSuite, 用于任意組合測(cè)試.
org.junit.runner.Suite
9. 參數(shù)化運(yùn)行器:
a) 使用注解@RunWith(value = Parameterized.class) 指定參數(shù)化運(yùn)行器,
b) 定義好一個(gè)方法,返回一組參數(shù)數(shù)據(jù),使用注解@Parameterized.Parameters
c) 測(cè)試類構(gòu)造方法中為各個(gè)參數(shù)賦值(構(gòu)造方法是由Junit調(diào)用的)
d) 方法必須是public,static,void,no-arg,返回一個(gè)Collection。
e) 方法中每個(gè)元素必須是一個(gè)一維數(shù)組,數(shù)組中第一個(gè)為預(yù)期值,之后參數(shù)一,參數(shù)二等。
@RunWith(value = Parameterized.class)
public class ParamCalculatorTest {
private Calculator cal;
private int expected;
private int para1;
private int para2;
@Parameterized.Parameters
public static Collection<Integer[]> getParamData() {
Integer[][] data = new Integer[][] { { 5, 3, 2 }, { 3, 1, 2 }, { 2, 1, 1 } };
return Arrays.asList(data);
}
@Before
public void init() {
cal = new Calculator();
}
public ParamCalculatorTest(int expected, int para1, int para2) {
this.expected = expected;
this.para1 = para1;
this.para2 = para2;
}
@Test
public void testAdd() {
int result = cal.add(para1, para2);
Assert.assertEquals(expected, result);
}
@After
public void destory() {
}
}
10.Suite運(yùn)行器:在Junit4中,如果想同時(shí)運(yùn)行多個(gè)測(cè)試,需要使用兩個(gè)注解:
@RunWith(value = Suite.class)
@SuiteClasses
使用以上兩個(gè)注解會(huì)通過(guò)Suite運(yùn)行器來(lái)執(zhí)行測(cè)試,在SuiteClasses中指定測(cè)試類,也可以繼續(xù)指定Suite,這樣Junit會(huì)在去查找里面的測(cè)試類并執(zhí)行。
@RunWith(value = Suite.class)
@SuiteClasses( { CalculatorTest.class, MyStackTest.class })
public class SuiteCalculatorMyStackTest {
… …
}
___________________________________________________________________________
Unit Test是由程序員本身來(lái)編寫(xiě)的。
以下介紹Junit單元測(cè)試框架:官網(wǎng)地址www.junit.org
JUnit是由 Erich Gamma 和 Kent Beck 編寫(xiě)的一個(gè)回歸測(cè)試框架(regression testing framework)。Junit測(cè)試是程序員測(cè)試,即所謂白盒測(cè)試,因?yàn)槌绦騿T知道被測(cè)試的軟件如何(How)完成功能和完成什么樣(What)的功能。
Junit3.x
___________________________________________________________________________
Junit3.x中使用包junit.framework.*
1. 必須繼承TestCase類
public class CalculatorTest extends TestCase {
private Calculator cal;
public CalculatorTest() {
}
public CalculatorTest(String name) {
super(name);
}
public void setUp() {
System.out.println("...........setUp..............");
cal = new Calculator();
}
public void testAdd() {
int result = cal.add(1, 2);
Assert.assertEquals("計(jì)算添加失敗", 3, result);
}
public void tearDown() {
System.out.println("........tearDown........");
}
}
2. 測(cè)試用例(Test Case)是單元測(cè)試的一個(gè)非常重要的方面。
3. 單元測(cè)試主要是用來(lái)判斷程序的執(zhí)行結(jié)果與自己期望的結(jié)果是否一致。
4. 在Junit3.x中,測(cè)試方法規(guī)則定義如下:
1) public
2) void
3) 無(wú)參數(shù)的
4) 測(cè)試方法名以test開(kāi)頭
5. Test Case之間一定要保持完全的獨(dú)立性,不允許出現(xiàn)任何的依賴關(guān)系。
6. 我們不能依賴于測(cè)試方法的執(zhí)行順序。
7. 關(guān)于setUp與tearDown方法的執(zhí)行順序:
1) setUp
2) testAdd
3) tearDown
8. Junit兩種類型錯(cuò)誤,F(xiàn)ailure 和 Error
Failure:指預(yù)期結(jié)果與實(shí)際結(jié)果不同,例如當(dāng)你使用assertEquals或者assertXXX方法斷言失敗時(shí),或者調(diào)用fail方法,就會(huì)報(bào)出Failure,這時(shí)要檢查測(cè)試方法邏輯設(shè)計(jì)是否有誤。
public void testDevide() {
System.out.println(".........testDevide()........");
int expected = 0;
int actual = 0;
try {
actual = cal.devide(1, 3);
} catch (Exception e) {
Assert.fail("測(cè)試失敗"); //不應(yīng)該執(zhí)行這段.
}
Assert.assertEquals(expected, actual);
}
Error:指程序在斷言執(zhí)行之前,程序就因?yàn)槟撤N錯(cuò)誤而引發(fā)異常,導(dǎo)致程序終止,例如測(cè)試方法中因拋出某個(gè)異常,使得測(cè)試方法無(wú)法正確執(zhí)行到斷言就結(jié)束,這時(shí)你要檢查測(cè)試的方法是否有未考慮到的情況而引起流程突然中斷。
也就是說(shuō)代碼中拋出了異常等影響代碼正常執(zhí)行的情況,比如ArrayIndexOfBoundsException、NullPointException,也可能是磁盤(pán)已滿、網(wǎng)絡(luò)中斷等等外部環(huán)境失敗所帶來(lái)的影響。
首先處理Error,然后在處理Failure.
9. 運(yùn)行測(cè)試用例
1) IDE中,如Eclipse工具已經(jīng)內(nèi)置了Junit,所以可以直接在測(cè)試類中鼠標(biāo)右鍵Run--Junit Test運(yùn)行。
2) 使用junit.textui.TestRunner類運(yùn)行測(cè)試類.
public static void main(String[] args) {
junit.textui.TestRunner.run(MyStackTest.class);
junit.textui.TestRunner.run(new CalculatorTest("testAdd"));
}
3) 使用TestSuite
a) 一次可以運(yùn)行多個(gè)測(cè)試類進(jìn)行測(cè)試
public class TestAll {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(OOOTest.class);
suite.addTestSuite(XXXTest.class);
suite.addTestSuite(YYYTest.class);
return suite;
}
public static void main(String[] args) {
TestRunner.run(suite());
}
}
b) 通過(guò)IDE自動(dòng)發(fā)現(xiàn)suite()方法,必須繼承TestCase
public class TestAll extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(OOOTest.class);
suite.addTestSuite(XXXTest.class);
suite.addTestSuite(YYYTest.class);
return suite;
}
}
c) 組合模式,組合方式多元化
……
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new XXXTest("testABC")); // 執(zhí)行testABC()方法
suite.addTest(YYYTest.suite()); // suite() 傳回TestSuite實(shí)例
suite.addTestSuite(OOOTest.class);//自動(dòng)查找OOOTest類中testXXX方法
return suite;
}
10.測(cè)試之前是什么狀態(tài),在測(cè)試執(zhí)行完成后就應(yīng)該是什么狀態(tài),而不應(yīng)該由于測(cè)試執(zhí)行的原因到導(dǎo)致了狀態(tài)發(fā)生了變化。
Junit4.x
___________________________________________________________________________
Junit4.x開(kāi)始支持Annotation注解技術(shù),在編寫(xiě)測(cè)試用例時(shí)簡(jiǎn)化不少動(dòng)作.
Junit4.x中使用的包org.junit.*
Junit4.x是兼容以前版本
Eclipse中自帶了Junit4,版本為junit4.3.1. BC-EC工程中使用的版本為Junit4.4,目前最新版本4.11
1. 無(wú)需繼承TestCase類,所有被@Test注解所修飾的public,void,無(wú)參數(shù)的方法都是測(cè)試用例,Junit自動(dòng)查找注解方法并執(zhí)行測(cè)試。
@Test
public void testAdd() {
int result = cal.add(1, 2);
Assert.assertEquals("計(jì)算添加失敗", 3, result);
}
2. 雖然Junit4.x中測(cè)試類中的方法名稱可以隨便取,但是建議跟junit3.x中測(cè)試類方法命名約定一致,統(tǒng)一方法名以test開(kāi)頭。
3. 使用@Before注解所修飾的方法同junit3.x中的setUp方法的功能,使用@After注解所修改的方法同junit3.x測(cè)試類中的tearDown方法的功能。 @Before和@After可以在多次指定.
@Before
public void init() {
System.out.println("...........setUp..............");
cal = new Calculator();
}
@After
public void destroy() {
System.out.println("........tearDown........");
}
4. 通過(guò)@BeforeClass和@AfterClass注解標(biāo)注public,static,void,無(wú)參數(shù)的類方法。在所有測(cè)試方法執(zhí)行之前和之后執(zhí)行。
@BeforeClass
public static void setUpBeforeClass() {
...
}
@AfterClass
public static void tearDownAfterClass() {
...
}
5. 使用@Ignore注解所修飾的方法(可以表示尚未編寫(xiě)完該用例或者想禁用該用例),運(yùn)行器會(huì)忽略該方法的測(cè)試;當(dāng)修飾類時(shí),運(yùn)行器會(huì)忽略掉所有測(cè)試方法。
@Test
@Ignore("尚未完成")
public void testMultiply() {
… …
}
Eclipse中Junit執(zhí)行結(jié)果中會(huì)提示如下:
6. 預(yù)期異常:
也可以使用在junit3.x中提到的fail()來(lái)測(cè)試預(yù)期拋出異常的情況。
public void testDevideByZero() {
Throwable tx = null;
try {
cal.devide(1, 0);
Assert.fail("應(yīng)該按預(yù)期拋出異常,測(cè)試失敗");
} catch (Exception e) {
tx = e;
}
Assert.assertNotNull(tx.getMessage());
Assert.assertEquals(ArithmeticException.class, tx.getClass());
Assert.assertEquals("除數(shù)不能為0!", tx.getMessage());
}
junit4中使用Test中的expected屬性達(dá)到相同的功能,代碼量小很多.
@Test(expected = ArithmeticException.class)
public void testDevideByZero() throws Exception {
cal.devide(1, 0); // 應(yīng)該拋出異常
}
7. 使用@Test(timeout = 2000) 注解預(yù)期某些操作應(yīng)該在指定時(shí)間內(nèi)完成,否則測(cè)試失敗。 單位是毫秒。
8. 測(cè)試運(yùn)行器:可以使用@RunWith注解使用的runner.
Junit4中內(nèi)置的運(yùn)行器有:
a) 附帶兼容junit3.x運(yùn)行器
org.junit.internal.runners.Junit38ClassRunner
b) 參數(shù)化運(yùn)行器,可設(shè)定一組參數(shù),每次運(yùn)行測(cè)試時(shí)自動(dòng)在指定位置給予不同的參數(shù)。
org.junit.runners.Parameterized
c) Suite運(yùn)行器,如同Junit3.x中的TestSuite, 用于任意組合測(cè)試.
org.junit.runner.Suite
9. 參數(shù)化運(yùn)行器:
a) 使用注解@RunWith(value = Parameterized.class) 指定參數(shù)化運(yùn)行器,
b) 定義好一個(gè)方法,返回一組參數(shù)數(shù)據(jù),使用注解@Parameterized.Parameters
c) 測(cè)試類構(gòu)造方法中為各個(gè)參數(shù)賦值(構(gòu)造方法是由Junit調(diào)用的)
d) 方法必須是public,static,void,no-arg,返回一個(gè)Collection。
e) 方法中每個(gè)元素必須是一個(gè)一維數(shù)組,數(shù)組中第一個(gè)為預(yù)期值,之后參數(shù)一,參數(shù)二等。
@RunWith(value = Parameterized.class)
public class ParamCalculatorTest {
private Calculator cal;
private int expected;
private int para1;
private int para2;
@Parameterized.Parameters
public static Collection<Integer[]> getParamData() {
Integer[][] data = new Integer[][] { { 5, 3, 2 }, { 3, 1, 2 }, { 2, 1, 1 } };
return Arrays.asList(data);
}
@Before
public void init() {
cal = new Calculator();
}
public ParamCalculatorTest(int expected, int para1, int para2) {
this.expected = expected;
this.para1 = para1;
this.para2 = para2;
}
@Test
public void testAdd() {
int result = cal.add(para1, para2);
Assert.assertEquals(expected, result);
}
@After
public void destory() {
}
}
10.Suite運(yùn)行器:在Junit4中,如果想同時(shí)運(yùn)行多個(gè)測(cè)試,需要使用兩個(gè)注解:
@RunWith(value = Suite.class)
@SuiteClasses
使用以上兩個(gè)注解會(huì)通過(guò)Suite運(yùn)行器來(lái)執(zhí)行測(cè)試,在SuiteClasses中指定測(cè)試類,也可以繼續(xù)指定Suite,這樣Junit會(huì)在去查找里面的測(cè)試類并執(zhí)行。
@RunWith(value = Suite.class)
@SuiteClasses( { CalculatorTest.class, MyStackTest.class })
public class SuiteCalculatorMyStackTest {
… …
}