JAVA第二次試驗

北京電子科技學院(BESTI)

??????????????

課程:Java程序設計 班級:1352??姓名:潘俊洋? 學號:20135230

成績:???????????? 指導教師:婁嘉鵬 ?????實驗日期:2015.5.4

實驗密級:???????? 預習程度:??????? ?實驗時間:

儀器組次:?? ???????必修/選修:??????? ??? 實驗序號:2

實驗名稱: ? ? ? ?Java面向對象程序設計

?

??

實驗儀器:

名稱

型號

數量

PC

?

1

?

?

?

?

實驗內容

1. 初步掌握單元測試和TDD

2. 理解并掌握面向對象三要素:封裝、繼承、多態

3. 初步掌握UML建模

4. 熟悉S.O.L.I.D原則

5. 了解設計模式

實驗要求

1.沒有Linux基礎的同學建議先學習《Linux基礎入門(新版)》《Vim編輯器》 課程

2.完成實驗、撰寫實驗報告,實驗報告以博客方式發表在博客園,注意實驗報告重點是運行結果,遇到的問題(工具查找,安裝,使用,程序的編輯,調試,運行等)、解決辦法(空洞的方法如“查網絡”、“問同學”、“看書”等一律得0分)以及分析(從中可以得到什么啟示,有什么收獲,教訓等)。報告可以參考范飛龍老師的指導

3. 嚴禁抄襲,有該行為者實驗成績歸零,并附加其他懲罰措施。

4.?請大家先在實驗樓中的~/Code目錄中用自己的學號建立一個目錄,代碼和UML圖要放到這個目錄中,截圖中沒有學號的會要求重做,然后跟著下面的步驟練習

實驗步驟

(一)單元測試

編程是智力活動,不是打字,編程前要把干什么、如何干想清楚才能把程序寫對、寫好。與目前不少同學一說編程就打開編輯器寫代碼不同,我希望同學們養成一個習慣,當你們想用程序解決問題時,要會寫三種碼:

  • 偽代碼
  • 產品代碼
  • 測試代碼

?

我們先寫偽代碼,偽代碼可以用漢語寫,推薦大家用英語寫,偽代碼與具體編程語言無關,不要寫與具體編程語言語法相關的語句(如用malloc分配內存,這樣只能用C語言編程了),偽代碼從意圖層面來解決問題,最終,偽代碼產品代碼最自然的、最好的注釋。想用編程來解決問題,首先要用偽代碼表明自己想明白了。 有了偽代碼,我們用特定編程語言翻譯一下,就是可用的產品代碼了。產品代碼寫完了,如果別人要使用這個代碼,把MyUtil.java拷給他就可以了。但是作為負責任的你,肯定會擔心自己的程序會有Bug。如果別人用自己的代碼發現一堆Bugs,那多沒面子!怎么辦?寫了產品代碼,我們還要寫測試代碼,證明自己的代碼沒有問題。Java編程時,程序員對類實現的測試叫單元測試。類XXXX單元測試,我們一般寫建一個XXXXTest的類,針對MyUtil類我們寫一個MyUtilTest.java的測試模塊。

這時測試都符合預期了,我們把MyUtil.java提供給別人使用時,心里比較有底氣了。那如何保證單元測度是充分的呢?我們的一般要求是測試代碼要比產品代碼多。如何寫測試,《單元測試之道》提出了Right-BICEP的方法,大家可以參考一下。 軟件是由多人合作完成的,不同人員的工作相互有依賴關系。軟件的很多錯誤都來源于程序員對模塊功能的誤解、疏忽或不了解模塊的變化。如何能讓自己負責的模塊功能定義盡量明確,模塊內部的改變不會影響其他模塊,而且模塊的質量能得到穩定的、量化的保證?單元測試就是一個很有效的解決方案。

(2) TDD(Test Driven Devlopment, 測試驅動開發)

我們先寫產品代碼,然后再寫測試代碼,通過測試發現了一些Bugs,提高了代碼質量。這有問題嗎?軟件開發從建筑中吸取了很多營養

工人是“先把墻砌好的,再用繩子測一下墻平不平,直不直,如果不平或不直拆了重砌”,還是“先用繩子給出平和直的標準,然后靠著繩子砌墻,從而保證了墻砌出來就是又平又直的”呢?答案是不言而喻的了。 拿編程做對比,我們是該“先寫產品代碼,然后再寫測試代碼,通過測試發現了一些Bugs,修改代碼”,還是該“先寫測試代碼,然后再寫產品代碼,從而寫出來的代碼就是正確的”呢?當然先寫測試代碼了。這種先寫測試代碼,然后再寫產品代碼的開發方法叫“測試驅動開發”(TDD)。TDD的一般步驟如下:

  • 明確當前要完成的功能,記錄成一個測試列表
  • 快速完成編寫針對此功能的測試用例
  • 測試代碼編譯不通過(沒產品代碼呢)
  • 編寫產品代碼
  • 測試通過
  • 對代碼進行重構,并保證測試通過(重構下次實驗練習)
  • 循環完成所有功能的開發

基于TDD,我們不會出現過度設計的情況,需求通過測試用例表達出來了,我們的產品代碼只要讓測試通過就可以了。

?

需求:我們要在一個MyUtil類中解決一個百分制成績轉成“優、良、中、及格、不及格”五級制成績的功能。

?

圖中的紅叉說明代碼存在語法錯誤,原因很簡單,MyUtil類還不存在,類中的percentage2fivegrade方法也不存在,我們在TDDDemosrc目錄中新建一個MyUtil的類,并實現percentage2fivegrade方法

測試結果出現了一個綠條(green bar),說明測試通過了。TDD的目標是"Clean Code That Works",TDD的slogan是"Keep the bar green, to Keep the code clean"

?

?

(二)面向對象三要素

(1)抽象

抽象一詞的本意是指人在認識思維活動中對事物表象因素的舍棄和對本質因素的抽取。抽象是人類認識復雜事物和現象時經常使用的思維工具,抽象思維能力在程序設計中非常重要,"去粗取精、化繁為簡、由表及里、異中求同"的抽象能力很大程度上決定了程序員的程序設計能力。
抽象就是抽出事物的本質特征而暫時不考慮他們的細節。對于復雜系統問題人們借助分層次抽象的方法進行問題求解;在抽象的最高層,可以使用問題環境的語言,以概括的方式敘述問題的解。在抽象的較低層,則采用過程化的方式進行描述。在描述問題解時,使用面向問題和面向實現的術語。 程序設計中,抽象包括兩個方面,一是過程抽象,二是數據抽象。

(2)封裝、繼承與多態

面向對象(Object-Oriented)的三要素包括:封裝、繼承、多態。面向對象的思想涉及到軟件開發的各個方面,如面向對象分析(OOA)、面向對象設計(OOD)、面向對象編程實現(OOP)。OOA根據抽象關鍵的問題域來分解系統,關注是什么(what)。OOD是一種提供符號設計系統的面向對象的實現過程,用非常接近問題域術語的方法把系統構造成“現實世界”的對象,關注怎么做(how),通過模型來實現功能規范。OOP則在設計的基礎上用編程語言(如Java)編碼。貫穿OOA、OOD和OOP的主線正是抽象。 OOD中建模會用圖形化的建模語言UML(Unified Modeling Language),UML是一種通用的建模語言,我們實驗中使用umbrello進行建模,Windows中推薦大家使用?StarUML。

過程抽象的結果是函數,數據抽象的結果是抽象數據類型(Abstract Data Type,ADT),類可以作具有繼承和多態機制的ADT。數據抽象才是OOP的核心和起源。

OO三要素的第一個要素是封裝,封裝就是將數據與相關行為包裝在一起以實現信息就隱藏。Java中用類進行封裝

我們可以用UML中的類圖來描述類Dog,首先我們在實驗樓的環境中打開shell,在命令行中輸入umbrello,打開UML建模軟件umbrello

我們可以看到,在UML 里,一個類的屬性能顯示它的名字,類型,初始化值,屬性也可以顯示private,public,protected。 類的方法能顯示它們的方法名,參數,返回類型,以及方法的private,public,protected屬性。其中:

  • +表示public
  • #表示 protected
  • -表示 private

使用UML可以讓我們不必關注細節。同樣,我們可以建立一個Cat

?

請大家注意UML類圖中繼承的表示法,是用一個帶三角的直線指向父類,通過繼承,我們消除了Dog類和Cat類中的重復代碼,符合DRY的要求。 繼承指一個類的定義可以基于另外一個已經存在的類,即子類基于父類,從而實現父類代碼的重用。既存類稱作基類、超類、父類(base class、super class、parent class),新類稱作派生類、繼承類、子類(derived class、inherited class、child class)。繼承關系表達了”Is a kind of“的關系,稱為“ISA”關系。繼承的關鍵在于確認子類為父類的一個特殊類型 。繼承是實現軟件可重用的根基,是提高軟件系統的可擴展性與可維護性的主要途徑。 如上面所示,以封裝為基礎,繼承可以實現代碼復用,需要注意的是,繼承更重要的作用是實現多態。 面向對象中允許不同類的對象對同一消息做出響應,即同一消息可以根據發送對象的不同而采用多種不同的行為方式,我們稱此現象為多態性。Java中,多態是指不同的類對象調用同一個簽名的成員方法時將執行不同代碼的現象。多態是面向對象程序設計的靈活性和可擴展性的基礎。 我們再看看上一個類圖,我們可以進一步抽象,把Dog類中的bark()Cat類中的meow()抽象成一個抽象方法shout(),Dog類和Cat類中覆蓋這個方法

?

(三)設計模式初步

(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,依賴倒置原則)

OCP是OOD中最重要的一個原則,OCP的內容是:

  • software entities (class, modules, function, etc.) should open for extension,but closed for modification.
  • 軟件實體(類,模塊,函數等)應該對擴充開放,對修改封閉。對擴充開放(Open For Extension )要求軟件模塊的行為必須是可以擴充的,在應用需求改變或需要滿足新的應用需求時,我們要讓模塊以不同的方式工作; 對修改封閉(Closed for Modification )要求模塊的源代碼是不可改動的,任何人都不許修改已有模塊的源代碼。 基于OCP,利用面向對象中的多態性(Polymorphic),更靈活地處理變更擁抱變化,OCP可以用以下手段實現:(1)抽象和繼承,(2)面向接口編程。 比如,在一個圖形系統中,已經存在三個模塊Shape,Square,Circle,如下圖所示

    LSP的內容是:

    • Subtypes must be substitutable for their base types
    • Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it
    • 子類必須可以被其基類所代
    • 使用指向基類的指針或引用的函數,必須能夠在不知道具體派生類對象類型的情況下使用它請大家想一想,Square類為何不能繼承Rectangle類,在數學上好像是沒有什么問題的呀。LSP告訴大家的一點是不要濫用繼承LSP原則清楚地指出,OOD中“ISA關系”是就行為功能而言。行為功能(behavior)不是內在的、私有的,而是外在、公開的,是客戶程序所依賴的接口。

      (2)模式與設計模式

      模式是某外在環境(Context) 下﹐對特定問題(Problem)的慣用解決之道(Solution)。模式必須使得問題明晰,闡明為什么用它來求解問題,以及在什么情況下有用,什么情況下不能起作用,每個模式因其重復性從而可被復用,本身有自己的名字,有可傳授性,能移植到不同情景下。模式可以看作對一個問題可復用的專家級解決方法。 計算機科學中有很多模式:

      • GRASP模式
      • 分析模式
      • 軟件體系結構模式
      • 設計模式:創建型,結構型,行為型
      • 管理模式: The Manager Pool 實現模式
      • 界面設計交互模式

      這里面最重要的是設計模式,在面向對象中設計模式的地位可以和面向過程編程中的數據結構的地位相當。

      (3)設計模式實示例

      設計模式(design pattern)提供一個用于細化軟件系統的子系統或組件,或它們之間的關系圖,它描述通信組件的公共再現結構,通信組件可以解決特定語境中的一個設計問題。如圖,隨著系統中對象的數量增多,對象之間的交互成指數增長,設計模式可以幫我們以最好的方式來設計系統。設計模式背后是抽象和SOLID原則。 設計模式有四個基本要素:

      • Pattern name:描述模式,便于交流,存檔
      • Problem:描述何處應用該模式
      • Solution:描述一個設計的組成元素,不針對特例
      • Consequence:應用該模式的結果和權衡(trade-offs)
      • 我們設計了一個文檔系統,如下圖UML類圖所示:圖片描述信息

      • ?

        對應的代碼如下:

        class Integer {
        int value;
        public Integer(){
        value=100;
        }
        public void DisplayValue(){
        System.out.println(value);
        }
        }
        class Document {
        Integer pi;
        public Document(){
        pi = new Integer();
        }
        public void DisplayData(){
        pi.DisplayValue();
        }
        }
        public class MyDoc{
        static Document d;
        public static void main(String [] args) {
        d = new Document();
        d.DisplayData();
        }
        }

      • 抽象工廠模式應用如下:圖片描述信息

        對應代碼如下:

        // Server Classes 
        abstract class Data { abstract public void DisplayValue(); } class Integer extends Data { int value; Integer() { value=100; } public void DisplayValue(){ System.out.println (value); } } // Pattern Classes abstract class Factory { abstract public Data CreateDataObject(); } class IntFactory extends Factory { public Data CreateDataObject(){ return new Integer(); } } //Client classes class Document { Data pd; Document(Factory pf){ pd = pf.CreateDataObject(); } public void DisplayData(){ pd.DisplayValue(); } } //Test class public class MyDoc { static Document d; public static void main(String[] args) { d = new Document(new IntFactory()); d.DisplayData(); } }

      • 我們看到通過增加了一層抽象層使代碼符合了OCP原則。代碼有良好的可擴充性、可維護性,代價是代碼多了,效率變低下了。 設計模式初學者容易過度使用它們,導致過度設計,也就是說,遵守DRY和OCP當然好,但會出現YAGNI(You aren't gonna need it, 你不會需要它)問題。 DRY原則和YAGNI原則并非完全兼容。前者追求"抽象化",要求找到通用的解決方法;后者追求"快和省",意味著不要把精力放在抽象化上面,因為很可能"你不會需要它"。怎么平衡呢?有一個Rule of three (三次原則):第一次用到某個功能時,你寫一個特定的解決方法;第二次又用到的時候,你拷貝上一次的代碼(違反了DRY);第三次出現的時候,你才著手"抽象化",寫出通用的解決方法。 設計模式學習先參考一下《深入淺出設計模式》,這本書可讀性非常好。

        除SOLID原則外還有很多其它的面向對象原則。如:

        • "組合替代繼承":這是說相對于繼承,要更傾向于使用組合;
        • "笛米特法則":這是說"你的類對其它類知道的越少越好";
        • "共同封閉原則":這是說"相關類應該打包在一起";
        • "穩定抽象原則":這是說"類越穩定,越應該由抽象類組成";

        當然,這些原則并不是孤立存在的,而是緊密聯系的,遵循一個原則的同時也就遵循了另外一個或多個原則;反之,違反了其中一個原則也很可能同時就違反了另外一個或多個原則。 設計模式是這些原則在一些特定場景的應用結果。因此,可以把設計模式看作"框架",把OOD原則看作"規范"。 在學習設計模式的過程中,要經常性的反思,這個設計模式體現了面向對象設計原則中的哪個或哪一些原則。 ??

      • (四)練習

        1使用TDD的方式設計關實現復數類Complex。

          • 偽代碼

          • 復數類ComplexNumber的方法:
            ComplexNumber():構造函數,將實部和虛部都置為0
            ComplexNumber(double r,double i):構造函數,通過參數r,i初始化實部和虛部

            complexAdd(ComplexNumber c):當前復數對象與參數對象相加,所得的結果也是復數,返回給此方法調用者
            complexMinus(ComplexNumber c):當前復數對象與參數對象相減,所得的結果也是復數,返回給此方法調用者
            complexMulti(ComplexNumber c):當前復數對象與參數對象相乘,所得的結果也是復數,返回給此方法調用者

          • 測試代碼
          • public class Test
            {
            public static void main(String args[])
            {

            ComplexNumber cNumber_1 =
            new ComplexNumber(3,-5);
            ComplexNumber
            cNumber_2 =
            new ComplexNumber(2,2);
            double d = 10.0;

            System.out.println(cNumber_1.toString() + " 加 "
            + cNumber_2.toString() + "
            等于 "
            + cNumber_1.complexAdd(cNumber_2).toString());

            System.out.println(cNumber_1.toString() + " 加 "
            + d + " 等于 "
            +
            cNumber_1.complexAdd(d).toString());
            System.out.println();

            System.out.println(cNumber_1.toString() + " 減 "
            + cNumber_2.toString() + "
            等于 "
            + cNumber_1.complexMinus(cNumber_2).toString());

            System.out.println(cNumber_1.toString() + " 減 "
            + d + " 等于 "
            +
            cNumber_1.complexMinus(d).toString());
            System.out.println();

            System.out.println(cNumber_1.toString() + " 乘 "
            + cNumber_2.toString() + "
            等于 "
            + cNumber_1.complexMulti(cNumber_2).toString());

            System.out.println(cNumber_1.toString() + " 乘 "
            + d + " 等于 "
            +
            cNumber_1.complexMulti(d).toString());
            System.out.println();

            System.out.println(cNumber_1.toString() + " 除 "
            + cNumber_2.toString() +
            "等于"
            + cNumber_1.complexDivision(cNumber_2).toString());

            System.out.println(cNumber_1.toString() + " 除 "
            + d + " 等于 "
            +
            cNumber_1.complexDivision(d).toString());
            }
            }
            class ComplexNumber
            {

            //復數運算方法
            //加
            ComplexNumber complexAdd(ComplexNumber
            c)
            {
            return new ComplexNumber(
            this.m_dRealPart +
            c.getRealPart(),
            this.m_dImaginPart +
            c.getImaginaryPart());
            }
            ComplexNumber complexAdd(double c)
            {

            return new ComplexNumber(
            this.m_dRealPart + c,
            this.m_dImaginPart);
            }
            //減
            ComplexNumber complexMinus(ComplexNumber
            c)
            {
            return new ComplexNumber(
            this.m_dRealPart -
            c.getRealPart(),
            this.m_dImaginPart -
            c.getImaginaryPart());
            }
            ComplexNumber complexMinus(double c)
            {

            return new ComplexNumber(
            this.m_dRealPart - c,
            this.m_dImaginPart);
            }
            //乘
            ComplexNumber complexMulti(ComplexNumber
            c)
            {
            return new ComplexNumber(
            this.m_dRealPart * c.getRealPart()

            - this.m_dImaginPart * c.getImaginaryPart(),
            this.m_dRealPart *
            c.getImaginaryPart()
            + this.m_dImaginPart *
            c.getRealPart());
            }
            ComplexNumber complexMulti(double c)
            {
            return
            new ComplexNumber(
            this.m_dRealPart * c, this.m_dImaginPart *
            c);
            }
            //除
            ComplexNumber complexDivision(ComplexNumber c){
            return
            new ComplexNumber((this.m_dRealPart*c.getRealPart()

            +this.m_dImaginPart*c.getImaginaryPart())

            /(c.getRealPart()*c.getRealPart()+c.getImaginaryPart()*c.getImaginaryPart()),

            (this.m_dImaginPart*c.getRealPart()

            -this.m_dRealPart*c.getImaginaryPart())

            /(c.getRealPart()*c.getRealPart()+c.getImaginaryPart()*c.getImaginaryPart()));

            }
            ComplexNumber complexDivision(double c){
            return new
            ComplexNumber(this.m_dRealPart/c,this.m_dImaginPart/c);
            }
            //toString()
            public String toString()
            {
            return "(" + m_dRealPart + " + "
            +
            m_dImaginPart + " i" + ")";
            }
            }

            • 產品代碼
            • public class Test
              {
              public static void main(String args[])
              {

              ComplexNumber cNumber_1 =
              new ComplexNumber(3,-5);
              ComplexNumber
              cNumber_2 =
              new ComplexNumber(2,2);
              double d = 10.0;

              System.out.println(cNumber_1.toString() + " 加 "
              + cNumber_2.toString() + "
              等于 "
              + cNumber_1.complexAdd(cNumber_2).toString());

              System.out.println(cNumber_1.toString() + " 加 "
              + d + " 等于 "
              +
              cNumber_1.complexAdd(d).toString());
              System.out.println();

              System.out.println(cNumber_1.toString() + " 減 "
              + cNumber_2.toString() + "
              等于 "
              + cNumber_1.complexMinus(cNumber_2).toString());

              System.out.println(cNumber_1.toString() + " 減 "
              + d + " 等于 "
              +
              cNumber_1.complexMinus(d).toString());
              System.out.println();

              System.out.println(cNumber_1.toString() + " 乘 "
              + cNumber_2.toString() + "
              等于 "
              + cNumber_1.complexMulti(cNumber_2).toString());

              System.out.println(cNumber_1.toString() + " 乘 "
              + d + " 等于 "
              +
              cNumber_1.complexMulti(d).toString());
              System.out.println();

              System.out.println(cNumber_1.toString() + " 除 "
              + cNumber_2.toString() +
              "等于"
              + cNumber_1.complexDivision(cNumber_2).toString());

              System.out.println(cNumber_1.toString() + " 除 "
              + d + " 等于 "
              +
              cNumber_1.complexDivision(d).toString());
              }
              }

              //復數運算方法
              //加
              ComplexNumber complexAdd(ComplexNumber
              c)
              {
              return new ComplexNumber(
              this.m_dRealPart +
              c.getRealPart(),
              this.m_dImaginPart +
              c.getImaginaryPart());
              }
              ComplexNumber complexAdd(double c)
              {

              return new ComplexNumber(
              this.m_dRealPart + c,
              this.m_dImaginPart);
              }
              //減
              ComplexNumber complexMinus(ComplexNumber
              c)
              {
              return new ComplexNumber(
              this.m_dRealPart -
              c.getRealPart(),
              this.m_dImaginPart -
              c.getImaginaryPart());
              }
              ComplexNumber complexMinus(double c)
              {

              return new ComplexNumber(
              this.m_dRealPart - c,
              this.m_dImaginPart);
              }
              //乘
              ComplexNumber complexMulti(ComplexNumber
              c)
              {
              return new ComplexNumber(
              this.m_dRealPart * c.getRealPart()

              - this.m_dImaginPart * c.getImaginaryPart(),
              this.m_dRealPart *
              c.getImaginaryPart()
              + this.m_dImaginPart *
              c.getRealPart());
              }
              ComplexNumber complexMulti(double c)
              {
              return
              new ComplexNumber(
              this.m_dRealPart * c, this.m_dImaginPart *
              c);
              }
              //除
              ComplexNumber complexDivision(ComplexNumber c){
              return
              new ComplexNumber((this.m_dRealPart*c.getRealPart()

              +this.m_dImaginPart*c.getImaginaryPart())

              /(c.getRealPart()*c.getRealPart()+c.getImaginaryPart()*c.getImaginaryPart()),

              (this.m_dImaginPart*c.getRealPart()

              -this.m_dRealPart*c.getImaginaryPart())

              /(c.getRealPart()*c.getRealPart()+c.getImaginaryPart()*c.getImaginaryPart()));

              }
              ComplexNumber complexDivision(double c){
              return new
              ComplexNumber(this.m_dRealPart/c,this.m_dImaginPart/c);
              }
              //toString()
              public String toString()
              {
              return "(" + m_dRealPart + " + "
              +
              m_dImaginPart + " i" + ")";
              }
              }

            • 單元測試的好處
            •  熟悉單元測試技術,了解相關的基本原理;

                掌握代碼,積累代碼編寫經驗,積累調試經驗,積累分析問題、解決問題的經驗;

                訓練動手能力,單元測試代碼不是業務代碼,開發、維護過程中不需要特別關注質量要求,底限是達到驗證業務代碼邏輯性的目的,因而比修改代碼要省心、省事;

                不需要準備項目運行環境,單元測試代碼在運行時的外部依賴比較少,執行驗證、調試代碼的代價會很低;

                降低新手程序員進入項目的門檻,有助于積累信心。

                項目過程中寫單元測試的好處

                一邊寫代碼,一邊檢查代碼中的小錯誤或者小疏忽,提前解決代碼中可能存在的筆誤;

                為了讓單元測試代碼更好寫,需要花點心思在思考類和方法的結構,好處是可以有效的提升代碼的可測試性,否則設計和結構不理想時,單元測試代碼寫作時也會比較麻煩,需要打很多樁;

                在集成測試前,有機會做驗證模塊內部的邏輯正確性,避免在聯調時花費過多的時間來解決小問題,提高聯調的效率;

                單元測試代碼對運行環境依賴小,不需要特別準備復雜的環境,外部模塊的行為和表現是可控制的,易于模擬異常場景;

                記錄已實現的特性,代碼即是最好的文檔,設計良好的單元測試代碼有助于后續維護,降低后期修改引入問題的可能性。

                維護或者學習代碼過程中寫單元測試的好處

                熟悉已有代碼的邏輯,變量的變化方式,代碼的運行軌跡,提高學習代碼的效率,降低通過看代碼來學習代碼的負擔;

                幫助重構,提高重構的成功率;

                輔助問題分析,遇到問題時,可以借助分析單元測試代碼來了解模塊的一般行為

轉載于:https://www.cnblogs.com/20135230pjy/p/4478117.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/375065.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/375065.shtml
英文地址,請注明出處:http://en.pswp.cn/news/375065.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【轉】怎么樣從一個瘋狂下載者成為一個學習者!!!值得反省下的問題·~~

為了方便廣大網友,各種網站也應運而生。當網絡的建設和發展正進行的如火如荼,喧鬧之中,搭配學習這壺美酒的,竟是一瓶名叫資料下載的毒藥,更糟糕的是,美酒和毒藥已經被灌到了同一個杯子里,渾然一…

靶場練習第八天~vulnhub靶場之CH4INRULZ_v1.0.1

一、前期準備 1.靶機下載 鏈接: 百度網盤 請輸入提取碼 提取碼: z37y 2.用命令ifconfig查看kali 二、信息收集 1.主機發現,使用nmap命令 具體使用方法:nmap -sP 192.168.101.0/24 2.查看該靶機開放了哪些端口 nmap -A 192.168.101.109 直接訪問80端…

C# 不支持關鍵字: “.;database”。

解決方案分析:這個一定是鏈接字符串有問題,核對web.config 和程序的字符串是否有誤轉載于:https://www.cnblogs.com/louby/p/5208986.html

TImus 1073 Square Country DP

題意&#xff1a;給出一個數n(1<n<60000),這個數可以寫成一些數的平方的和&#xff0c; 問對于n&#xff0c;最少可以分成多少個數的平方的和。 比如&#xff1a;n344&#xff0c;則34418*184*42*2&#xff0c;輸出3. dp[i]表示i這個數最少可以分成多少個數的平方的和。 …

vulnhub靶機獲取不到ip

1.啟動靶機&#xff0c;出現如下圖所示&#xff0c;按e 2.進入如下圖所示時&#xff0c;將ro 替換為 rw signie init/bin/bash 3.按下Ctrl鍵X鍵&#xff0c;重啟服務進入如下界面 4.查看當前網卡IP信息 ip a 5.編輯網卡配置文件vi /etc/network/interfaces 6.發現網卡名字與剛…

apache整合tomcat部署集群

近日&#xff0c;由于公司項目需要&#xff0c;所以學習了apache整合tomcat以及集群的一些知識。 所以做下筆記日后回顧可以用到。 apache只有處理靜態事物的能力&#xff0c; 而tomcat的強項就是處理動態的請求&#xff0c;所以apache和tomcat整合相互取長補短&#xff0c;由a…

Cpk

CPK&#xff1a;Complex Process Capability index 的縮寫&#xff0c;是現代企業用于表示制程能力的指標。制程能力是過程性能的允許最大變化范圍與過程的正常偏差的比值。制程能力研究在於確認這些特性符合規格的程度&#xff0c;以保證制程成品不符規格的不良率在要求的水準…

靶場練習第九天~vulnhub靶場之dc-1

一、環境搭建 靶場下載鏈接: 百度網盤 請輸入提取碼 提取碼: ih67 1.查看kali的ip&#xff1a;ifconfig 二、信息收集 1.使用namp命令 主機探測: nmap -sP 192.168.101.0/24 查看靶機開放端口號和服務:nmap -A 192.168.101.111 發現開放80端口,訪問一下192.168.101.111 Dru…

4~20mA模擬輸出(電流環)應用筆記(轉)

4~20mA模擬輸出&#xff08;電流環&#xff09;應用筆記 bpesun163.com 前言 4-20mA.DC(1-5V.DC)信號制是國際電工委員會(IEC):過程控制系統用模擬信號標準。 在工業現場&#xff0c;如果采集的信號經調理后是電壓信號并且進行長線傳輸&#xff0c;會產生以下問題&#xff1a; …

ADO多線程數據庫查詢

ADO多線程數據庫查詢通常會出現3個問題&#xff1a;1、CoInitialize 沒有調用 &#xff08;CoInitialize was not called&#xff09;&#xff1b;所以&#xff0c;在使用任何dbGo對象前&#xff0c;必須手 調用CoInitialize和CoUninitialize。調用CoInitialize失敗會產生"…

PHPExcel

excel文檔處理對象主要用來管理我們的excel文檔&#xff0c;怎么來管理&#xff08;通過屬性和方法來管理&#xff09;&#xff1f;大家知道&#xff0c;類主要是由屬性和方法來組成&#xff0c;通過php程序的手段來管理excel文檔&#xff0c;其實就是通過本對象的屬性和方法來…

靶場練習第十天~vulnhub靶場之dc-2

一、準備工作 靶機下載地址鏈接: 百度網盤 請輸入提取碼 提取碼: ib86 二、信息收集 1.nmap的信息收集 &#xff08;1&#xff09;使用nmap 192.168.101.0/24&#xff0c;發現靶機地址為192.168.101.115 &#xff08;2&#xff09;對靶機做進一步探測&#xff0c;發現靶機開…

Ubuntu 14.10 創建虛擬網卡實現橋接網絡

目標需求&#xff1a;在Ubuntu主機創建一張虛擬網卡&#xff0c;使得搭建在VirtualBox中的其他主機能借助虛擬網卡構建的局域網進行相互間的通訊 步驟一&#xff1a;準備工具包 安裝 uml-utilities 以及 bridge-utils sudo apt-get install uml-utilities bridge-utils 步驟二&…

iOS定時器-- NSTimer 和CADisplaylink

iOS定時器-- NSTimer 和CADisplaylink 一、iOS中有兩種不同的定時器&#xff1a; 1. NSTimer&#xff08;時間間隔可以任意設定&#xff0c;最小0.1ms&#xff09;// If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 millisecond…

靶場練習第十一天~vulnhub靶場之dc-3

一、準備工作 1.靶場鏈接: 百度網盤 請輸入提取碼 提取碼: 48d3 2.啟動靶場后會遇到如下情況&#xff1a; 2-1具體解決辦法如下&#xff1a; 啟動成功 3.查看kali的ip&#xff1a;ifconfig 二、信息收集 1.nmap的信息收集 &#xff08;1&#xff09;尋找靶機的ip&#xf…

UNIX環境高級編程一書中apue.h找不到

apue.h是作者為了方便自己寫的一個庫&#xff0c;在http://www.apuebook.com選擇你對應書中的source code&#xff0c;然后解壓壓縮包中在/include/apue.h以及/lib/error.c復制到你文件系統中/usr/include中即可。另外在apue.h中#include "error.c"即可。這樣gcc編譯…

大齡程序員怎樣渡過中年危機?(轉)

大齡程序員怎樣渡過中年危機&#xff1f; 作者前言&#xff1a; 話說再有十幾天就進入2016年了&#xff0c;想到這&#xff0c;我不由得五味雜陳。2016年對我來說是一個特殊的年份&#xff0c;因為我即將40歲了&#xff0c;人生正式告別青年期&#xff0c;進入中年了。 在娛樂圈…

靶場練習第十二天~vulnhub靶場之dc-4

一、準備工作 1.靶機下載鏈接 鏈接: 百度網盤 請輸入提取碼 提取碼: 3hq4 2.用ifconfig查看kali的ip 二、信息收集 1.nmap的信息收集 &#xff08;1&#xff09;主機發現 命令&#xff1a;nmap 192.168.101.0/24 &#xff08;2&#xff09;掃描靶機詳細信息 發現主機 192…

網絡命令-nc(二)

繼續Netcat 這個命令吧 1&#xff1a;遠程拷貝文件 在本地輸出 文件debian.img 到 192.168.5.40 主機12345端口監聽 nc -v 192.168.5.40 12345 < debian.img 在192.168.5.40 主機12345端口監聽&#xff0c;將文件指定為debian-copy.img nc -l -v 12345 > debian-copy.im…

靶場練習第十三天~vulnhub靶場之dc-5

一、準備工作 1.靶機環境搭建 下載鏈接: https://pan.baidu.com/s/1csvuJ_NVCBvVr75KhxyM3Q?pwdxie7 提取碼: xie7 2.kali的ip 命令&#xff1a;ifconfig 3.kali和靶機的都設置為NAT模式 二、信息收集 1.nmap的信息收集 &#xff08;1&#xff09;尋找靶機的ip 命令&…