<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### 添加更多測試 現在,我們應該繼續添加更多測試。我遵循的風格是:觀察class該做的所有事情,然后針對任何一項功能的任何一種可能失敗情況,進行測試。這不同于某些程序 員提倡的「測試所有public函數」。記住,測試應該是一種風險驅動(risk driven)行為,測試的目的是希望找出現在或未來可能出現的錯誤。所以我不會去測試那些僅僅讀或寫一個值域的訪問函數(accessors),因為它們太簡單了,不大可能出錯。 這一點很重要,因為如果你撰寫過多測試,結果往往測試量反而不夠。我常常閱讀許多測試相關書籍,我的反應是:測試需要做那么多工作,令我退避三舍。這種書起不了預期效果,因為它讓你覺得測試有大量工作要做。事實上,哪怕只做一點點測試,你也能從中受益。測試的要訣是:測試你最擔心出錯的部分。這樣你就能從測試工作中得到最大利益。 TIP:編寫未臻完善的測試并實際運行,好過對完美測試的無盡等待。 現在,我的目光落到了read()。它還應該做些什么?文檔上說,當input stream到達文件尾端,應該返回-1 (在我看來這并不是個很好的協議,不過我猜這會讓C程序員倍感親切)。讓我們來測試一下。我的文本編輯器告訴我,我的測試文件共有141個字符,于是我撰寫測試代碼如下: ~~~ public void testReadAtEnd() throws IOException { int ch = -1234; for (int i = 0; i < 141; i++) ch = _input.read(); assertEquals(-1, ch); } ~~~ 為了讓這個測試運行起來,我必須把它添加到test suit(測試套件)中: ~~~ public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new FileReaderTester("testRead")); suite.addTest(new FileReaderTester("testReadAtEnd")); return suite; } ~~~ 當test suit (測試套件)運行起來,它會告訴我它的每個成分——也就是這兩個test cases (測試用例)——的運行情況。每個用例都會調用tearDown(),然后執行測試代碼,最終調用tearDown()。每次測試都調用setUp()和tearDown()是很重要的,因為這樣才能保證測試之間彼此隔離。也就是說我們可以按任意順序運行它們,不會對它們的結果造成任何影響。 老要記住將test cases添加到suite(),實在是件痛苦的事。幸運的是Erich Gamma和Kent Beck和我一樣懶,所以他們提供了一條途徑來避免這種痛苦。TestSuite class有個特殊構造函數,接受一個class為參數,創建出來的test suite會將該class內所有以"test"起頭的函數都當作test cases包含進來。如果遵循這一命名習慣, 就可以把我的main()改為這樣: ~~~ public static void main (String[] args) { junit.textui.TestRunner.run (new TestSuite(FileReaderTester.class)); } ~~~ 這樣,我寫的每一個測試函數便都被自動添加到test suit 中。 測試的一項重要技巧就是「尋找邊界條件」。對read()而言,邊界條件應該是第一個字符、最后一個字符、倒數第二個字符: ~~~ public void testReadBoundaries()throwsIOException { assertEquals("read first char",'B', _input.read()); int ch; for (int i = 1;i <140; i++) ch = _input.read(); assertEquals("read last char",'6',_input.read()); assertEquals("read at end",-1,_input.read()); } ~~~ 你可以在assertions中加入一條消息。如果測試失敗,這條消息就會被顯示出來。 TIP:考慮可能出錯的邊界條件,把測試火力集中在那兒。 「尋找邊界條件」也包括尋找特殊的、可能導致測試失敗的情況。對于文件相關測 試,空文件是個不錯的邊界條件: ~~~ public void testEmptyRead()throws IOException { File empty = new File ("empty.txt"); FileOutputStream out = new FileOutputStream (empty); out.close(); FileReader in = new FileReader (empty); assertEquals (-1, in.read()); } ~~~ 現在我為這個測試產生一些額外的訪對test fixture (測試裝備)。如果以后還需要空文件,我可以把這些代碼移至setUp(),從而將「空文件」加入常規test fixture。 ~~~ protected void setUp(){ try { _input = new FileReader("data.txt"); _empty = newEmptyFile(); } catch(IOException e){ throw new RuntimeException(e.toString()); } } private FileReader newEmptyFile() throws IOException { File empty = new File ("empty.txt"); FileOutputStream out = new FileOutputStream(empty); out.close(); return newFileReader(empty); } public void testEmptyRead() throws IOException { assertEquals (-1, _empty.read()); } ~~~ 如果讀取文件末尾之后的位置,會發生什么事?同樣應該返回-1。現在我再加一個測試來探測這一點: ~~~ public void testReadBoundaries()throwsIOException { assertEquals("read first char",'B', _input.read()); int ch; for (int i = 1;i <140; i++) ch = _input.read(); assertEquals("read last char", '6', _input.read()); assertEquals("read at end",-1,_input.read()); assertEquals ("readpast end", -1, _input.read()); } ~~~ 注意,我在這里扮演「程序公敵」的角色。我積極思考如何破壞代碼。我發現這種思維能夠提高生產力,并且很有趣。它縱容了我心智中比較促狹的那一部分。 測試時,別忘了檢查預期的錯誤是否如期出現。如果你嘗試在stream被關閉后再讀 取它,就應該得到一個IOException異常,這也應該被測試出來: ~~~ public void testReadAfterClose() throwsIOException{ _input.close(); try { _input.read(); fail ("no exception for read past end"); } catch (IOException io) {} } ~~~ IOException之外的任何異常都將以一般方式形成一個錯誤。 TIP: 當事情被大家認為應該會出錯時,別忘了檢查彼時是否有異常如預期般地被拋出。 請遵循這些規則,不斷豐富你的測試。對于某些比較復雜的,可能你得花費 一些時間來瀏覽其接口,但是在此過程中你可以真正理解這個接口。而且這對于考慮錯誤情況和邊界情況特別有幫助。這是在編寫代碼的同時(甚至之前)編寫測試代碼的另一個好處。 隨著tester classes愈來愈多,你可以產生另一個class,專門用來包含「由其他tester classes所形成」的測試套件(test suite)。這很容易做到,因為一個測試套件本來就可以包含其他測試套件。這樣,你就可以擁有一個「主控的」(master)test class: ~~~ class MasterTester extends TestCase { public static void main (String[] args) { junit.textui.TestRunner.run (suite()); } public static Test suite() { TestSuite result = new TestSuite(); result.addTest(new TestSuite(FileReaderTester.class)); result.addTest(new TestSuite(FileWriterTester.class)); // and so on... return result; } } ~~~ 什么時候應該停下來?我相信這樣的話你聽過很多次:「任何測試都不能證明一個程序沒有臭蟲」。這是真的,但這不會影響「測試可以提高編程速度」。我曾經見過數種測試規則建議,其目的都是保證你能夠測試所有情況的一切組合。這些東西值得一看,但是別讓它們影響你。當測試數量達到一定程度之后,測試效益就會呈現遞減態勢,而非持續遞增;如果試圖編寫太多測試,你也可能因為工作量太大而氣餒,最后什么都寫不成。你應該把測試集中在可能出錯的地方。觀 察代碼,看哪兒變得復雜;觀察函數,思考哪些地方可能出錯。是的,你的測試不可能找出所有臭蟲,但一旦進行重構,你可以更好地理解整個程序,從而找到更多臭蟲。雖然我總是以單獨一個測試套件開始重構,但前進途中我總會加入更多測試。 TIP:不要因為「測試無法捕捉所有臭蟲」,就不撰寫測試代碼,因為測試的確可以描捉到大多數臭蟲。 對象技術有個微妙處:繼承(inheritance)和多態(polymorphism )會讓測試變得比較困難,因為將有許多種組合需要測試。如果你有3個彼此合作的abstract classes ,每個abstract classes 有三個subclasses,那么你總共擁有九個可供選擇的classes,和27種組合。我并不總是試著測試所有可能組合,但我會盡量測試每一個classes,這可以大大減少各種組合所造成的風險。如果這些classes之間彼此有合理的獨立性,我很可能不會嘗試所有組合。是的,我總有可能遺漏些什么,但我覺得「花合理時間抓出大多數臭蟲」要好過「窮盡一生抓出所有臭蟲」。 測試代碼和產品代碼(待測代碼)之間有個區別:你可以放心地拷貝、編輯測試代 碼。處理多種組合情況以及面對多個可供選擇的classes時,我經常這么做。首先測試「標準發薪過程」,然后加上「資歷」和「年底前停薪」條件,然后又去掉這兩個條件……。只要在合理的測試裝備(test fixture)上準備好一些簡單的替換樣本,我就能夠很快生成不同的test case (測試用例),然后就可以利用重構手法分解出真正常用的各種東西。 我希望這一章能夠讓你對于「撰寫測試代碼」有一些感覺。關于這個主題,我可以說上很多,但如果那么做,就有點喧賓奪主了。總而言之,請構筑一個良好的臭蟲檢測器(bug detector)并經常運行它;這對任何開發工作都是一個美好的工具,并且是重構的前提。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看