標籤:
一、實驗內容
1. 初步掌握單元測試和TDD
2. 理解並掌握物件導向三要素:封裝、繼承、多態
3. 初步掌握UML建模
4. 熟悉S.O.L.I.D原則
5. 瞭解設計模式
二、實驗要求
1.沒有Linux基礎的同學建議先學習《Linux基礎入門(新版)》《Vim編輯器》 課程
2.完成實驗、撰寫實驗報告,實驗報告以部落格方式發表在部落格園,注意實驗報告重點是運行結果,遇到的問題(工具尋找,安裝,使用,程式的編輯,調試,運行等)、解決辦法(空洞的方法如“查網路”、“問同學”、“看書”等一律得0分)以及分析(從中可以得到什麼啟示,有什麼收穫,教訓等)。報告可以參考範飛龍老師的指導
3. 嚴禁抄襲,有該行為者實驗成績歸零,並附加其他懲罰措施。
4. 請大家先在實驗樓中的~/Code目錄中用自己的學號建立一個目錄,代碼和UML圖要放到這個目錄中,中沒有學號的會要求重做,然後跟著下面的步驟練習。
三、實驗步驟
(一)單元測試
(1) 三種代碼
我們通過一個例子說明如何寫這三種代碼。
需求:我們要在一個MyUtil類中解決一個百分製成績轉成“優、良、中、及格、不及格”五級製成績的功能。
//虛擬碼:
百分制轉五分制:
如果成績小於60,轉成“不及格”
如果成績在60與70之間,轉成“及格”
如果成績在70與80之間,轉成“中等”
如果成績在80與90之間,轉成“良好”
如果成績在90與100之間,轉成“優秀”
其他,轉成“錯誤”
//產品代碼:
翻譯好的MyUtil.java如下:
public class MyUtil{
public static String percentage2fivegrade(int grade){
//如果成績小於60,轉成“不及格”
if (grade < 60)
return "不及格";
//如果成績在60與70之間,轉成“及格”
else if (grade < 70)
return "及格";
//如果成績在70與80之間,轉成“中等”
else if (grade < 80)
return "中等";
//如果成績在80與90之間,轉成“良好”
else if (grade < 90)
return "良好";
//如果成績在90與100之間,轉成“優秀”
else if (grade < 100)
return "優秀";
//其他,轉成“錯誤”
else
return "錯誤";
}
}
//測試代碼:
public class MyUtilTest {
public static void main(String[] args) {
// 百分製成績是50時應該返回五級制的“不及格”
if(MyUtil.percentage2fivegrade(50) != "不及格")
System.out.println("test failed!");
else
System.out.println("test passed!");
}
}
(2) TDD(Test Driven Devlopment, 測試驅動開發)
先寫測試代碼,然後再寫產品代碼的開發方法叫“測試驅動開發”(TDD)。TDD的一般步驟如下:
- 明確當前要完成的功能,記錄成一個測試清單
- 快速完成編寫針對此功能的測試案例
- 測試代碼編譯不通過(沒產品代碼呢)
- 編寫產品代碼
- 測試通過
- 對代碼進行重構,並保證測試通過(重構下次實驗練習)
- 迴圈完成所有功能的開發
基於TDD,我們不會出現過度設計的情況,需求通過測試案例表達出來了,我們的產品代碼只要讓測試通過就可以了。 Java中有單元測試工具JUnit來輔助進行TDD,我們用TDD的方式把前面百分制轉五分制的例子重寫一次,體會一下有測試載入器支援的開發的好處。 開啟Eclipse,單擊File->New->Java Project建立一個TDDDemo的Java項目:我們在TDDDemo項目中,把滑鼠放到項目名TDDDemo上,單擊右鍵,在彈出的菜單中選定New->Source Folder建立一個測試目錄test,我們把滑鼠放到test目錄上,單擊右鍵,在彈出的菜單中選定New->JUnit Test Case建立一個測試案例類MyUtilTest,
我們增加第一個測試案例testNormal,注意測試案例前一定要有註解@Test,測試案例方法名任意,輸入以下代碼:
import org.junit.Test;
import junit.framework.TestCase;
public class MyUtilTest extends TestCase {
@Test
public void testNormal() {
assertEquals("不及格", MyUtil.percentage2fivegrade(55));
assertEquals("及格", MyUtil.percentage2fivegrade(65));
assertEquals("中等", MyUtil.percentage2fivegrade(75));
assertEquals("良好", MyUtil.percentage2fivegrade(85));
assertEquals("優秀", MyUtil.percentage2fivegrade(95));
}
}
輸入完畢
紅叉說明代碼存在語法錯誤,原因很簡單,MyUtil類還不存在,類中的percentage2fivegrade方法也不存在,我們在TDDDemo的src目錄中建立一個MyUtil的類,並實現percentage2fivegrade方法
現在測試代碼沒有語法錯誤了,我們把滑鼠放到MyUtilTest.java上,單擊右鍵,選擇Run as->JUnit Test
測試結果出現了一個綠條(green bar),說明測試通過了。
TDD的編碼節奏是:
- 增加測試代碼,JUnit出現紅條
- 修改產品代碼
- JUnit出現綠條,任務完成
(二)物件導向三要素
(1)抽象
(2)封裝、繼承與多態
(三)設計模式初步
(1)S.O.L.I.D原則
物件導向三要素是“封裝、繼承、多態”,任何物件導向程式設計語言都會在文法上支援這三要素。如何藉助抽象思維用好三要素特別是多態還是非常困難的,S.O.L.I.D類設計原則是一個很好的指導:
- SRP(Single Responsibility Principle,單一職責原則)
- OCP(Open-Closed Principle,開放-封閉原則)
- LSP(Liskov Substitusion Principle,Liskov替換原則)
- ISP(Interface Segregation Principle,介面分離原則)
- DIP(Dependency Inversion Principle,依賴倒置原則)
(四)練習
1使用TDD的方式設計關實現複數類Complex。
2.實驗報告中統計自己的PSP(Personal Software Process)時間
| 步驟 |
耗時 |
百分比 |
需求分析 |
30min |
12.5% |
設計 |
50min |
21% |
代碼實現 |
60min |
25% |
測試 |
60min |
25% |
分析總結 |
40min |
16.5% |
3. 實現要有虛擬碼,產品代碼,測試代碼。
4.總結單元測試的好處
四、實驗
五、練習題
虛擬碼:
//複數類
類有虛部實部
複數的加法運算
複數的減法運算
複數的乘法運算
複數的除法運算
產品代碼:
public class ComplexDemo {
// main方法
public static void main(String[] a) {
Complex b = new Complex(2, 5);
Complex c = new Complex(3, -4);
System.out.println(b + "+" + c + "=" + b.add(c));
System.out.println(b + "-" + c + "=" + b.minus(c));
System.out.println(b + "*" + c + "=" + b.multiply(c));
System.out.println(b + "/" + c + "=" + b.divide(c));
}
}
// Complex類
class Complex {
private double m;// 實部
private double n;// 虛部
public Complex(double m, double n) {
this.m = m;
this.n = n;
}
// add
public Complex add(Complex c) {
return new Complex(m + c.m, n + c.n);
}
// minus
public Complex minus(Complex c) {
return new Complex(m - c.m, n - c.n);
}
// multiply
public Complex multiply(Complex c) { return new Complex(m * c.m - n * c.n, m * c.n + n * c.m);
}
// divide
public Complex divide(Complex c) {
double d = Math.sqrt(c.m * c.m) + Math.sqrt(c.n * c.n);
return new Complex((m * c.m + n * c.n) / d, Math.round((m * c.n - n * c.m) / d));
}
public String toString() {
String rtr_str = "";
if (n > 0)
rtr_str = "(" + m + "+" + n + "i" + ")";
if (n == 0)
rtr_str = "(" + m + ")";
if (n < 0)
rtr_str = "(" + m + n + "i" + ")";
return rtr_str;
}
}
測試代碼:
public static ComplexTest{
public static void main(String[] args){
class Complex {
private double m;// 實部
private double n;// 虛部
public Complex(double m, double n) {
this.m = m;
this.n = n;
}
public String toString() {
String rtr_str = "";
if (n > 0)
rtr_str = "(" + m + "+" + n + "i" + ")";
if (n == 0)
rtr_str = "(" + m + ")";
if (n < 0)
rtr_str = "(" + m + n + "i" + ")";
return rtr_str;
}
}
}
}
六、遇到的問題及解決方案
出現的問題:首先是從實驗一開始就不能正常使用實驗樓,然後自己就先暫時放棄了實驗樓,因為實驗第一部分內容並不是非實驗樓環境不可;
其次就是在後來熟悉UML的過程中,網速太慢,導致整個過程進行的特別的緩慢,而且因為自己的心急,老是出現錯誤,比如多打了括弧,或者手誤刪掉了內容。本來想挽回,就開始按撤銷,最終不明原因的回到的案頭,然後之前所有的東西都消失。目前這個還是沒解決,因此就自己從頭開始,而且後來還把箭頭給弄反了,目前還不知道該怎麼辦。
還有就是在測試代碼的編寫過程中因為不熟悉這種編程過程所以不太會編寫,最後是自己對照著產品代碼來寫的測試代碼,所以測試代碼出現了很多問題,花費了很多時間去修改和編寫代碼最終還是無法順利運行。
七、總結及體會
本次實驗進行實踐耗時太長,不僅僅是網路的問題,主要還是自己不熟悉實驗環境和實驗內容。另外,單元測試的好處在於它可以使編寫的程式的人不斷地考慮去多種程式可能出現的問題,能讓這個程式更加可靠,思維更加全面,讓使用者使用得更加順利。在編寫代碼方面還是有些問題,沒有在腦海中形成正確的編程思路,代碼一改再改。在以後的實踐當中還需要努力,一次次的失敗終將給與我大量的經驗。
java實驗2實驗報告(20135131)