NO IMAGE

開心一笑

【朋友病了,要掛鹽水。給他扎針的是一個實習小護士,紮了半天都沒扎進血管。
他痛得齜牙咧嘴,無奈叫來了護士長。
護士長好手法,只見她一針見血地扎進了血管,然後馬上拔出來,
把針遞給那個實習護士說:“看清楚沒有?你再試一次!”】

視訊教程

大家好,我錄製的視訊《Java之優雅程式設計之道》已經在CSDN學院釋出了,有興趣的同學可以購買觀看,相信大家一定會收穫到很多知識的。謝謝大家的支援……

視訊地址:http://edu.csdn.net/lecturer/994

提出問題

如何優雅編寫測試程式碼???

解決問題

1)TDD(測試驅動開發),意思是先寫單元測試,然後寫對應的程式碼,通過修改除錯讓寫的程式碼通過單元測試。使用TDD,會使測試覆蓋所有的程式碼,測試程式碼和生產程式碼的比例有可能會達到1:1 ,所以也會帶來成本的問題,所有我們要保持測試的整潔。

2)單元測試的好處:讓程式碼可擴充套件,可維護,可複用。

3)整潔測試的三要素 :可讀性、可讀性、可讀性。

4)每個測試都可以拆分為三個環節:構造測試資料、操作測試資料、檢驗操作是否達到預期結果。

5)雙重標準:測試環境中和生產環境中有些條件不必完全一致。生產環境中有時要考慮記憶體、CPU等效能問題,而在測試環境中不必做這些限制。

6)一個測試一個斷言,不必完全糾結,但單個測試斷言數應該最小化,只測試一個概念,還是單一職責的問題;

7)F.I.R.S.T原則

  • F Fast:測試需要頻繁執行,因此要能快速執行;

  • I Independent:測試應該相互獨立;

  • R Repeatable:測試應當能在任何環境中重複;

  • S Self-validating:自足驗證,測試應該能看到成功與否的結果;

  • T Timely:測試應該及時編寫,應該恰好在生產程式碼之前編寫;

下面用一個例子說明上面的理論(理論很枯燥,例項很美好):

package com.hwy.test;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class CodeCleanTest {
@Test
public void testBuySnacks(){
List<String> snacks =  buySnacks();
Assert.assertEquals("購買零食有問題,請檢查!!!",true,snacks.size()>0);
}
@Test
public void testEatSnacks(){
/** 這個是我們自己構建的零食資料,肯定不會出現null等問題 **/
/** 我們不要呼叫buySnacks方法,因為還是單一職責的問題,只測試一個概念**/
List<String> snacks =  getSnacks();
Assert.assertEquals("沒有一起吃3個零食", 3, eatSnacks(snacks));
}
@Test
public void testDropLitter(){
List<String> snacks =  getSnacks();
Assert.assertEquals("垃圾沒有扔掉!!!",true,dropLitter(snacks));
}
@Test
public void testDateWithGirl() throws Exception{
Assert.assertEquals("約會失敗了", true, dateWithGirl());
}
/**
* 構建零食資料(事實這些註釋都是不需要,只是為了大家理解)
* @return
*/
public List<String> getSnacks(){
List<String> snacksList = new ArrayList<>();
snacksList.add("牛奶");
snacksList.add("巧克力");
snacksList.add("土豆片");
return snacksList;
}
/**
* 買零食(事實這些註釋都是不需要,只是為了大家理解)
* @return
*/
public List<String> buySnacks(){
List<String> snacksList = new ArrayList<>();
snacksList.add("牛奶");
snacksList.add("巧克力");
snacksList.add("土豆片");
/** 這裡故意顯示為空 **/
//return null;
return snacksList;
}
/**
* 約會
*/
public boolean dateWithGirl() throws Exception {
boolean isSuccess = false;
List<String> snacksList =  buySnacks();
/** 利用逆向思維,丟擲一個業務異常,這裡我只是用簡單的exception代替 **/
if(null == snacksList || snacksList.size() ==0){
throw new Exception("你沒買到零食或買到的零食有問題,請檢查!");
}
/** 程式碼執行到這一步就說明snacksList不為null,之後的所有
* 操作都不用判斷snacksList是否為空 **/
List<String> litter =  eatSnacks(snacksList);
dropLitter(litter);
isSuccess = true;
return isSuccess;
}
/**
* 吃零食(事實這些註釋都是不需要,只是為了大家理解)
* @param snacks
*/
public List<String> eatSnacks(List<String> snacks){
for (String snack : snacks) {
System.out.println("一起吃"   snack);
}
return snacks;
}
/**
* 仍垃圾(事實這些註釋都是不需要,只是為了大家理解)
* @param litter
*/
public boolean dropLitter(List<String> litter){
boolean isDrop = false;
for(String snack:litter){
System.out.println("扔掉垃圾:"   snack);
}
/** 這裡故意寫的有點冗餘,只是方便大家學習 **/
isDrop = true;
return isDrop;
}
}

上面的每個測試方法都是:test 原方法名稱,一般測試方法都是這麼命名的。同時上面的測試方法,沒給方法都是獨立的,只測試一個概念。

下面舉一個錯誤的例項:

package com.hwy.test;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class CodeCleanTest {
@Test
public void testBuySnacks() throws Exception{
/** 像這樣子,在一個測試方法中,測試太多的方法,造成測試用例難以複用 **/
/** 這樣不符合每個測試一個斷言的規則,同時也不符合F.I.R.S.T原則**/
List<String> snacks =  buySnacks();
Assert.assertEquals("購買零食有問題,請檢查!!!",true,snacks.size()>0);
Assert.assertEquals("沒有一起吃3個零食", 3, eatSnacks(snacks));
Assert.assertEquals("垃圾沒有扔掉!!!",true,dropLitter(snacks));
Assert.assertEquals("約會失敗了", true, dateWithGirl());
}
/**
* 構建零食資料(事實這些註釋都是不需要,只是為了大家理解)
* @return
*/
public List<String> getSnacks(){
List<String> snacksList = new ArrayList<>();
snacksList.add("牛奶");
snacksList.add("巧克力");
snacksList.add("土豆片");
return snacksList;
}
/**
* 買零食(事實這些註釋都是不需要,只是為了大家理解)
* @return
*/
public List<String> buySnacks(){
List<String> snacksList = new ArrayList<>();
snacksList.add("牛奶");
snacksList.add("巧克力");
snacksList.add("土豆片");
/** 這裡故意顯示為空 **/
//return null;
return snacksList;
}
/**
* 約會
*/
public boolean dateWithGirl() throws Exception {
boolean isSuccess = false;
List<String> snacksList =  buySnacks();
/** 利用逆向思維,丟擲一個業務異常,這裡我只是用簡單的exception代替 **/
if(null == snacksList || snacksList.size() ==0){
throw new Exception("你沒買到零食或買到的零食有問題,請檢查!");
}
/** 程式碼執行到這一步就說明snacksList不為null,之後的所有
* 操作都不用判斷snacksList是否為空 **/
List<String> litter =  eatSnacks(snacksList);
dropLitter(litter);
isSuccess = true;
return isSuccess;
}
/**
* 吃零食(事實這些註釋都是不需要,只是為了大家理解)
* @param snacks
*/
public List<String> eatSnacks(List<String> snacks){
for (String snack : snacks) {
System.out.println("一起吃"   snack);
}
return snacks;
}
/**
* 仍垃圾(事實這些註釋都是不需要,只是為了大家理解)
* @param litter
*/
public boolean dropLitter(List<String> litter){
boolean isDrop = false;
for(String snack:litter){
System.out.println("扔掉垃圾:"   snack);
}
/** 這裡故意寫的有點冗餘,只是方便大家學習 **/
isDrop = true;
return isDrop;
}
}

讀書感悟

來自《窮查理智慧書》

  • 忙碌的人們很少有閒客來訪;沸騰的鍋裡絕不會落入蒼蠅。
  • 失意時,沒有人瞭解;得意時,不瞭解自己。
  • 憤怒總是有一定的理,但很少有好的道理。
  • 你可能有時犯大錯,是因為你認為自己永遠正確。
  • 一百個小偷,也偷不走一個人的臉皮,特別是當這個人沒有臉皮的話。
  • 人們經常把自己看錯了,卻很少把自己忘記了。
  • 無人認錯的爭吵必然延續無盡。
  • 如果你的祕密不想被敵人知道,請先對你的朋友保密。
  • 教訓換來的一兩智慧,勝過書本一斤的知識。

其他

如果有帶給你一絲絲小快樂,就讓快樂繼續傳遞下去,歡迎轉載,點贊,頂,歡迎留下寶貴的意見,多謝支援!