單元測(cè)試的重要性
- 什么是單元測(cè)試
單元測(cè)試是對(duì)軟件組成單元進(jìn)行測(cè)試,其目的是檢驗(yàn)軟件基本組成單位的正確性,測(cè)試的對(duì)象是軟件設(shè)計(jì)的最小單位:函數(shù)。(維基百科) - 單元測(cè)試的好處:
- 減少Bug率,防止被公司扣績(jī)效;
- 更新代碼時(shí),減少重復(fù)的工作
- 可以極速地進(jìn)行回歸測(cè)試
- 快速定位Bug,配合使用Debug
單元測(cè)試做什么?
- 接口功能性測(cè)試: 接口功能的正確性,即保證接口能夠被正常調(diào)用,并輸出有效數(shù)據(jù)!
例如:是否被順利調(diào)用\參數(shù)是否符合預(yù)期 - 局部數(shù)據(jù)結(jié)構(gòu)測(cè)試:保證數(shù)據(jù)結(jié)構(gòu)的正確性
例如:變量是否有初始值或在某場(chǎng)景下是否有默認(rèn)值\變量是否溢出 - 邊界條件測(cè)試:測(cè)試
變量無(wú)賦值(null)
變量是數(shù)值或字符
主要邊界:最大值,最小值,無(wú)窮大
溢出邊界:在邊界外面取值+/-1
臨近邊界:在邊界值之內(nèi)取值+/-1
字符串的邊界,引用 "變量字符"的邊界
字符串的設(shè)置,空字符串
字符串的應(yīng)用長(zhǎng)度測(cè)試
空白集合
目標(biāo)集合的類型和應(yīng)用邊界
集合的次序
變量是規(guī)律的,測(cè)試無(wú)窮大的極限,無(wú)窮小的極限 - 異常模塊測(cè)試:(缺陷測(cè)試),后續(xù)處理模塊測(cè)試:是否包閉當(dāng)前異常或者對(duì)異常形成消化,是否影響結(jié)果!
TDD、ATDD、BDD&RBE
在目前比較流行的敏捷開(kāi)發(fā)模式(如極限編程、Scrum方法等)中,推崇“測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(Test Driven Development,TDD)” 測(cè)試在先、編碼在后的開(kāi)發(fā)實(shí)踐。
- 在代碼層次,在編碼之前寫測(cè)試腳本,可以稱為單元測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(Unit Test Driven Development,UTDD)
-
在業(yè)務(wù)層次,在需求分析時(shí)就確定需求(如用戶故事)的驗(yàn)收標(biāo)準(zhǔn),即驗(yàn)收測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(Acceptance Test Driven Development,ATDD)。
TDD流程
UTDD從根本上改變了開(kāi)發(fā)人員的編程態(tài)度,開(kāi)發(fā)人員不能在像過(guò)去那樣隨意寫代碼,要求寫的每行代碼都是有效的代碼,寫完所有的代碼就意味著真正完成了編碼任務(wù)。
TDD一改以往的破壞性測(cè)試的思維方式,測(cè)試在先、編碼在后,更符合“缺陷預(yù)防”的思想。
JUnit簡(jiǎn)介
JUnit 是用于編寫和運(yùn)行可重復(fù)的自動(dòng)化測(cè)試的開(kāi)源測(cè)試框架,這樣可以保證我們的代碼按預(yù)期工作。JUnit 可廣泛用于工業(yè)和作為支架(從命令行)或IDE(如 IDEA)內(nèi)單獨(dú)的 Java 程序。
- 斷言測(cè)試預(yù)期結(jié)果。
- 測(cè)試功能共享通用的測(cè)試數(shù)據(jù)。
- 測(cè)試套件輕松地組織和運(yùn)行測(cè)試。
- 圖形和文本測(cè)試運(yùn)行。
JUnit 用于測(cè)試:
- 整個(gè)對(duì)象
- 對(duì)象的一部分 - 交互的方法或一些方法
- 幾個(gè)對(duì)象之間的互動(dòng)(交互)
JUnit 特點(diǎn)
- JUnit 是用于編寫和運(yùn)行測(cè)試的開(kāi)源框架。
- 提供了注釋,以確定測(cè)試方法。
- 提供斷言測(cè)試預(yù)期結(jié)果。
- 提供了測(cè)試運(yùn)行的運(yùn)行測(cè)試。
- JUnit 測(cè)試讓您可以更快地編寫代碼,提高質(zhì)量
- JUnit 是優(yōu)雅簡(jiǎn)潔。它是不那么復(fù)雜以及不需要花費(fèi)太多的時(shí)間。
- JUnit 測(cè)試可以自動(dòng)運(yùn)行,檢查自己的結(jié)果,并提供即時(shí)反饋。沒(méi)有必要通過(guò)測(cè)試結(jié)果報(bào)告來(lái)手動(dòng)梳理。
- JUnit 測(cè)試可以組織成測(cè)試套件包含測(cè)試案例,甚至其他測(cè)試套件。
- Junit 顯示測(cè)試進(jìn)度的,如果測(cè)試是沒(méi)有問(wèn)題條形是綠色的,測(cè)試失敗則會(huì)變成紅色。
JUnit 注解
@BeforeClass 全局只會(huì)執(zhí)行一次,而且是第一個(gè)運(yùn)行
@Before 在測(cè)試方法運(yùn)行之前運(yùn)行
@Test 測(cè)試方法
@After 在測(cè)試方法運(yùn)行之后允許
@AfterClass 全局只會(huì)執(zhí)行一次,而且是最后一個(gè)運(yùn)行
@Ignore 忽略此方法
@AfterClass和BeforeClass即是為了滿足測(cè)試中,那些體積非常大,但只要一次初始化的代碼塊!
測(cè)試方法必須是靜態(tài)
注意:編寫測(cè)試類的原則:
①測(cè)試方法上必須使用@Test進(jìn)行修飾
②測(cè)試方法必須使用public void 進(jìn)行修飾,不能帶任何的參數(shù)
③新建一個(gè)源代碼目錄來(lái)存放我們的測(cè)試代碼,即將測(cè)試代碼和項(xiàng)目業(yè)務(wù)代碼分開(kāi)
④測(cè)試類所在的包名應(yīng)該和被測(cè)試類所在的包名保持一致
⑤測(cè)試單元中的每個(gè)方法必須可以獨(dú)立測(cè)試,測(cè)試方法間不能有任何的依賴
⑥測(cè)試類使用Test作為類名的后綴(不是必須)
⑦測(cè)試方法使用test作為方法名的前綴(不是必須)
第一個(gè)JUnit
@Test
public void sayHello() {
App app = new App();
String result = app.sayHello("girl");
}
JUnit 斷言
斷言是編程術(shù)語(yǔ),表示為一些布爾表達(dá)式,程序員相信在程序中的某個(gè)特定點(diǎn)該表達(dá)式值為真,可以在任何時(shí)候啟用和禁用斷言驗(yàn)證,因此可以在測(cè)試時(shí)啟用斷言而在部署時(shí)禁用斷言。同樣,程序投入運(yùn)行后,最終用戶在遇到問(wèn)題時(shí)可以重新啟用斷言。
使用斷言可以創(chuàng)建更穩(wěn)定、品質(zhì)更好且 不易于出錯(cuò)的代碼。當(dāng)需要在一個(gè)值為 false 時(shí)中斷當(dāng)前操作的話,可以使用斷言。單元測(cè)試必須使用斷言(Junit/JunitX)。
常用斷言方法
| 斷言 | 描述 |
|---|---|
| void assertEquals([String message], expected value, actual value) | 斷言兩個(gè)值相等。值可能是類型有 int, short, long, byte, char or java.lang.Object. 第一個(gè)參數(shù)是一個(gè)可選的字符串消息 |
| void assertTrue([String message], boolean condition) | 斷言一個(gè)條件為真 |
| void assertFalse([String message],boolean condition) | 斷言一個(gè)條件為假 |
| void assertNotNull([String message], java.lang.Object object) | 斷言一個(gè)對(duì)象不為空(null) |
| void assertNull([String message], java.lang.Object object) | 斷言一個(gè)對(duì)象為空(null) |
| void assertSame([String message], java.lang.Object expected, java.lang.Object actual) | 斷言,兩個(gè)對(duì)象引用相同的對(duì)象 |
| void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) | 斷言,兩個(gè)對(duì)象不是引用同一個(gè)對(duì)象 |
| void assertArrayEquals([String message], expectedArray, resultArray) | 斷言預(yù)期數(shù)組和結(jié)果數(shù)組相等。數(shù)組的類型可能是 int, long, short, char, byte or java.lang.Object. |
測(cè)試斷言效果
在之前的單元測(cè)試類中創(chuàng)建一個(gè)名為 testAssert 方法來(lái)查看斷言效果
/**
* 測(cè)試斷言
*/
@Test
public void testAssert() {
String obj1 = "junit";
String obj2 = "junit";
String obj3 = "test";
String obj4 = "test";
String obj5 = null;
int var1 = 1;
int var2 = 2;
int[] arithmetic1 = {1, 2, 3};
int[] arithmetic2 = {1, 2, 3};
assertEquals(obj1, obj2);
assertSame(obj3, obj4);
assertNotSame(obj2, obj4);
assertNotNull(obj1);
assertNull(obj5);
assertTrue("為真", var1 == var2);
assertArrayEquals(arithmetic1, arithmetic2);
}
Junit vs TestNG
- TestNG與JUnit的相同點(diǎn):
使用annotation,且大部分annotation相同。
都可以進(jìn)行單元測(cè)試(Unit test)。
都是針對(duì)Java測(cè)試的工具。 - TestNG與JUnit的不同點(diǎn):
JUnit只能進(jìn)行單元測(cè)試,TestNG可以進(jìn)行單元測(cè)試,功能測(cè)試,端到端測(cè)試,集成測(cè)試等,主要是因?yàn)閠estNG
存在depends可以進(jìn)行測(cè)試用例的組合;
TestNG需要一個(gè)額外的xml配置文件,配置測(cè)試的class、method甚至package。
TestNG的運(yùn)行方式更加靈活:命令行、ant和IDE,JUnit只能使用IDE。TestNG有自己的命令行執(zhí)行方式。
TestNG的annotation更加豐富和易懂,比如@ExpectedExceptions、@DataProvider等。
測(cè)試套件運(yùn)行失敗,JUnit 4會(huì)重新運(yùn)行整個(gè)測(cè)試套件。TestNG運(yùn)行失敗時(shí),會(huì)創(chuàng)建一個(gè)XML文件說(shuō)明失敗的測(cè)試,利用這個(gè)文件執(zhí)行程序,就不會(huì)重復(fù)運(yùn)行已經(jīng)成功的測(cè)試。
Spring整合Junit
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.suoron</groupId>
<artifactId>JunitSpring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
單元測(cè)試類
@RunWith(SpringJUnit4ClassRunner.class) //表示整合JUnit4進(jìn)行測(cè)試
@ContextConfiguration(locations = "classpath:spring-context.xml") //加載spring配置文件
public class AppTest2 {
private String flag;
@Resource
ApplicationContext context;
