<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        在Python編程過程中用單元測試法調試代碼的介紹

        來源:懂視網 責編:小采 時間:2020-11-27 14:39:57
        文檔

        在Python編程過程中用單元測試法調試代碼的介紹

        在Python編程過程中用單元測試法調試代碼的介紹:對于程序開發新手來說,一個最常見的困惑是測試的主題。他們隱約覺得單元測試是很好的,而且他們也應該做單元測試。但他們卻不懂這個詞的真正含義。如果這聽起來像是在說你,不要怕!在這篇文章中,我將介紹什么是單元測試,為什么它有用,以及如何對Pyt
        推薦度:
        導讀在Python編程過程中用單元測試法調試代碼的介紹:對于程序開發新手來說,一個最常見的困惑是測試的主題。他們隱約覺得單元測試是很好的,而且他們也應該做單元測試。但他們卻不懂這個詞的真正含義。如果這聽起來像是在說你,不要怕!在這篇文章中,我將介紹什么是單元測試,為什么它有用,以及如何對Pyt

        對于程序開發新手來說,一個最常見的困惑是測試的主題。他們隱約覺得“單元測試”是很好的,而且他們也應該做單元測試。但他們卻不懂這個詞的真正含義。如果這聽起來像是在說你,不要怕!在這篇文章中,我將介紹什么是單元測試,為什么它有用,以及如何對Python的代碼進行單元測試。

        什么是測試?

        在討論為什么測試很有用、怎樣進行測試之前,讓我們先花幾分鐘來定義一下“單元測試”究竟是什么。在一般的編程術語中,“測試”指的是通過編寫可以調用的代碼(獨立于你實際應用程序的代碼)來幫助你確定程序中是否有錯誤。這并不能證明你的代碼是正確的(在非常有限的情況下這是唯一的可能)。它只是報告了測試者認為的那種情況是否被正確處理了。

        注:當我使用“測試”一次時,我指的是“自動化測試”,即這些測試是在機器上運行的。“手動測試”則是一個人運行程序,并與它進行交互,從而發現漏洞,這是個獨立的概念。

        測試可以檢查出什么樣的情況呢?語法錯誤是語言的意外誤用,如

        my_list..append(foo)
        

        后面多余的一個 “.“。邏輯錯誤是當算法(可以看成是“解決問題的方式”)不正確時引發的。可能程序員忘記Python是“零索引“的并且試圖通過寫

        print(my_string[len(my_string)])
        

        (這樣會引起IndexError)來打印出一個字符串中的最后一個字符。更大、更系統的錯誤也可以被檢查出來。比如當用戶輸入一個大于100的數字、或者在網站檢索不可用的時候掛起此網站的話,程序會一直崩潰。

        這些所有的錯誤都可以通過對代碼的仔細測試檢查出來。Unit testing,特指在一個分隔的代碼單元中的測試。一個單元可以是整個模塊,一個單獨的類或者函數,或者這兩者間的任何代碼。然而,重要的是,測試代碼要與我們沒有測試到的其他代碼相互隔離(因為其它代碼本身有錯誤的話會因此混淆測試結果)。考慮如下例子:

        def is_prime(number):
         """Return True if *number* is prime."""
         for element in range(number):
         if number % element == 0:
         return False
         
         return True
         
        def print_next_prime(number):
         """Print the closest prime number larger than *number*."""
         index = number
         while True:
         index += 1
         if is_prime(index):
         print(index)
        

        你有兩個函數,is_prime和print_next_prime。如果你想測試print_next_prime,我們就需要確定is_prime是正確的,因為print_next_prime中調用了這個函數。在這種情況下,print_next_prime函數是一個單元,is_prime函數是另一個單元。由于單元測試每次只測試一個單元,因此我們需要仔細考慮怎樣才能準確的測試print_next_prime?(更多的是關于之后怎樣實現這些測試)。

        因此,測試代碼應該長什么樣呢?如果上一個例子存在一個叫primes.py的文件中,我們可以把測試代碼寫在一個叫test_primes.py的文件中。下面是test_primes.py 中的最基本內容,比如下面這個測試樣例:

        import unittest
        from primes import is_prime
         
        class PrimesTestCase(unittest.TestCase):
         """Tests for `primes.py`."""
         
         def test_is_five_prime(self):
         """Is five successfully determined to be prime?"""
         self.assertTrue(is_prime(5))
         
        if __name__ == '__main__':
         unittest.main()
        

        這個文件通過一個test case :? test_is_five_prime. 創建了一個單元測試。通過Python內嵌的一個測試框架unittest。當unittest.main()被調用時,任何一個以test開頭命名的成員函數將被運行,他們是unittest.TestCase的一個派生類,并且是斷言檢查的。如果我們通過輸入python test_primes.py來運行測試,我們能夠看到unittest框架在控制臺上 的輸出:

        $ python test_primes.py
        E
        ======================================================================
        ERROR: test_is_five_prime (__main__.PrimesTestCase)
        ----------------------------------------------------------------------
        Traceback (most recent call last):
        File "test_primes.py", line 8, in test_is_five_prime
         self.assertTrue(is_prime(5))
        File "/home/jknupp/code/github_code/blug_private/primes.py", line 4, in is_prime
         if number % element == 0:
        ZeroDivisionError: integer division or modulo by zero
         
        ----------------------------------------------------------------------
        Ran 1 test in 0.000s
        

        單獨的“E”表示的是我們單元測試的結果(如果它成功了,會打印出一個“.”)。我們可以看到我們的測試失敗了,以及導致失敗的那行代碼,還有任何引發的異常信息。

        為什么要測試?

        在我們繼續那個例子之前,要問個很重要的問題:“為什么測試對我來說有價值”?這是個公平的問題,也是那些對于代碼測試不熟悉的人常問的問題。畢竟,測試需要一定的時間,而我們完全可以用這些時間去編代碼,為什么要測試而不是去做那些最有生產效率的事?

        有很多答案可以有效的回答這個問題,我列出了以下幾點:

        測試可以保證你的代碼在一系列給定條件下正常工作

        測試確保了一系列條件下的正確性。語法錯誤基本上一定通過測試被查出來,一個代碼單元的基本的邏輯也可以通過測試被檢測出來,以確保一定條件下的正確性。再次,它不是要證明代碼是在任何條件下都正確的。我們只是簡單的瞄準了一套比較完整的可能的條件(例如,你可以寫一個測試來監測當你調用my_addition_function(3, 'refrigerator), 的時候,但你不必為每個參數檢測所有可能的字符串)

        測試允許人們確保對代碼的改動不會破壞現有的功能

        重構代碼時,這一點特別有用。如果沒有測試到位,你就沒法保證你的代碼的改變沒有破壞之前工作正常的東西。如果你希望更改或重寫你的代碼,并希望不會破壞任何東西,適當的單元測試是很必要的。

        測試迫使人們在不尋常條件的情況下思考代碼,這可能會揭示出邏輯錯誤

        編寫測試強迫你去思考在非正常條件下你的代碼可能遇到的問題。在上面的例子中,my_addition_function函數可以將兩個數字相加。測試基本正確性的簡單測試將調用my_addition_function(2,2),并斷言說結果是4。然而,進一步的測試可能會通過調用my_addition_function(2.0,2.0)來測試該功能是否能正確進行浮點數的運算。防御性的編碼原則表明你的代碼應該能夠在非法輸入的情況下正常失效,因此測試時,當字符串類型被作為參數傳遞到函數中時應當拋出一個異常。

        良好的測試要求模塊化,解耦代碼,這是一個良好的系統設計的標志

        單元測試的整體做法是通過代碼的松散耦合使其變得更容易。如果你的應用程序代碼直接調用數據庫,例如,測試你應用程序的邏輯依賴于一個有效的數據庫連接,并且測試數據要存在于數據庫中。另一方面,隔離了外部資源的代碼在測試過程中更容易被模擬對象所替代。出于必要,(人們)設計的有測試能力的應用程序最終采用了模塊化和松散耦合。

        單元測試的剖析

        通過繼續之前的例子,我們將看到如何編寫并組織單元測試。回想一下,primes.py包含以下代碼:

        def is_prime(number):
         """Return True if *number* is prime."""
         for element in range(number):
         if number % element == 0:
         return False
         
         return True
         
        def print_next_prime(number):
         """Print the closest prime number larger than *number*."""
         index = number
         while True:
         index += 1
         if is_prime(index):
         print(index)
        
        

        同時,文件test_primes.py包含如下代碼:

        import unittest
        from primes import is_prime
         
        class PrimesTestCase(unittest.TestCase):
         """Tests for `primes.py`."""
         
         def test_is_five_prime(self):
         """Is five successfully determined to be prime?"""
         self.assertTrue(is_prime(5))
         
        if __name__ == '__main__':
         unittest.main()
        

        做出斷言

        unittest是Python標準庫中的一部分,并且也是我們開始“單元測試之旅”的一個好的起點。一個單元測試中包括一個或多個斷言(一些聲明被測試代碼的一些屬性為真的語句)。會想你上學的時候“斷言”這個詞的字面意思就是“陳述事實”。在單元測試中,斷言也是同樣的作用。

        self.assertTrue 更像是自我解釋。它能聲明傳遞過去的參數的計算結果為真。unittest.TestCase類包含了許多斷言方法,所以一定要檢查列表并選擇合適的方法進行測試。如果在每個測試中都用到assertTrue的話,則應該考慮一個反模式,因為它增加了測試中讀者的認知負擔。正確使用斷言的方法應當是使測試能夠明確說明究竟是什么在被斷言(例如,很明顯?,只需掃一眼assertIsInstance 的方法名,就知道它要說明的是其參數)。

        每個測試應該測試一個單獨、有具體特性的代碼,并且應該被賦予相關的命名。就單元測試發現機制的研究表明(主要在Python2.7+和3.2+版本中),測試方法應該以test_為前綴命名。(這是可配置的,但是其目的是鑒別測試方法和非測試的實用方法)。如果我們把test_is_five_prime 的命名改為is_five_prime的話,運行python中的test_primes.py時會輸出如下信息:

        $ python test_primes.py
         
        ----------------------------------------------------------------------
        Ran 0 tests in 0.000s
         
        OK
        

        不要被上面信息中的“OK”所糊弄了,只有當什么測試都沒真正運行的時候才會顯示出“OK”!我認為一個測試也沒跑其實應該顯示個報錯的,但是個人感覺放在一邊,這是一個你應該注意是行為,尤其是當通過程序運行來檢查測試結果的時候(例如,一個持續的集成工具,像TracisCI)。

        異常

        讓我們回到test_primes.py的實際內容中去,回憶一下運行python test_primes.py指令后的輸出結果:

        $ python test_primes.py
        E
        ======================================================================
        ERROR: test_is_five_prime (__main__.PrimesTestCase)
        ----------------------------------------------------------------------
        Traceback (most recent call last):
        File "test_primes.py", line 8, in test_is_five_prime
         self.assertTrue(is_prime(5))
        File "/home/jknupp/code/github_code/blug_private/primes.py", line 4, in is_prime
         if number % element == 0:
        ZeroDivisionError: integer division or modulo by zero
         
        ----------------------------------------------------------------------
        Ran 1 test in 0.000s
        

        這些輸出告訴我們,我們一個測試的結果失敗并不是因為一個斷言失敗了,而是因為出現了一個未捕獲的異常。事實上,由于拋出了一個異常,unittest框架并沒有能夠運行我們的測試就返回了。

        這里的問題很明確:我們使用的求模運算的計算范圍中包括了0,因此執行了一個除以0的操作。為了解決這個問題,我們可以很簡單的將起始值由0變為2,并指出對0求模是錯誤的,而對1求模則一直是真(并且一個素數只能被自身和1整除,因此我們無需檢查1)。

        解決問題

        一次失敗的測試使我們修改了代碼。一旦我們改好了這個錯誤(將s_prime中的一行改為for element in range(2, number):),我們就得到了如下輸出:

        $ python test_primes.py
        .
        ----------------------------------------------------------------------
        Ran 1 test in 0.000s
        

        現在錯誤已經改了,這是不是意味著我們應該刪掉test_is_five_prime這個測試方法(因為很明顯,它將不會一直能通過測試)?不應該刪。由于通過測試是最終目標的話單元測試應該盡量少的被刪除。我們已經測試過is_prime的語法是有效的,并且,至少在一種情況下,它返回正確的結果。我們的目標是要建立一套能全部通過的(單元測試的邏輯分組)測試,雖然有些一開始可能會失敗。

        test_is_five_prime用于處理一個“非特殊”的素數。讓我們確保它也能正確處理非素數。將以下方法添加到PrimesTestCase類:

        def test_is_four_non_prime(self):
         """Is four correctly determined not to be prime?"""
         self.assertFalse(is_prime(4), msg='Four is not prime!')
        

        請注意,這時我們給assert調用添加了可選的msg參數。如果該測試失敗了,我們的信息將被打印到控制臺,并給運行測試的人提供額外的信息。

        邊界情況

        我們已經成功的測試了兩種普通情況。現在讓我們考慮邊界情況下、或者那些不尋常或意外的輸入的用例。當測試一個其范圍是正整數的函數時,邊界情況下的實例包括0、1、負數和一個很大的數字。現在讓我們來測試其中的一些。

        添加一個對0的測試很簡單。我們預計?is_prime(0)返回的是false,因為,根據定義,素數必須大于1。

        def test_is_zero_not_prime(self):
         """Is zero correctly determined not to be prime?"""
         self.assertFalse(is_prime(0))
        

        可惜呀,輸出是:

        python test_primes.py
        ..F
        ======================================================================
        FAIL: test_is_zero_not_prime (__main__.PrimesTestCase)
        Is zero correctly determined not to be prime?
        ----------------------------------------------------------------------
        Traceback (most recent call last):
        File "test_primes.py", line 17, in test_is_zero_not_prime
         self.assertFalse(is_prime(0))
        AssertionError: True is not false
         
        ----------------------------------------------------------------------
        Ran 3 tests in 0.000s
         
        FAILED (failures=1)
        

        0被錯誤的判定為素數。我們忘記了,我們決定在數字范圍中跳過0和1。讓我們增加一個對他們的特殊檢查。

        def is_prime(number):
         """Return True if *number* is prime."""
         if number in (0, 1):
         return False
         
         for element in range(2, number):
         if number % element == 0:
         return False
         
         return True
        

        現在測試通過了。我們的函數應該怎樣處理一個負數?在寫這個測試用例之前就知道輸出結果是很重要的。在這種情況下,任何負數都應該返回false。

        def test_negative_number(self):
         """Is a negative number correctly determined not to be prime?"""
         for index in range(-1, -10, -1):
         self.assertFalse(is_prime(index))
        

        這里我們覺得檢查從-1到-9的所有數字。在一個循環中調用test方法是非常合法的,在一個測試中多次調用斷言方法也可以。我們可以在下面用(更詳細)的方式改寫代碼。

        def test_negative_number(self):
         """Is a negative number correctly determined not to be prime?"""
         self.assertFalse(is_prime(-1))
         self.assertFalse(is_prime(-2))
         self.assertFalse(is_prime(-3))
         self.assertFalse(is_prime(-4))
         self.assertFalse(is_prime(-5))
         self.assertFalse(is_prime(-6))
         self.assertFalse(is_prime(-7))
         self.assertFalse(is_prime(-8))
         self.assertFalse(is_prime(-9))
        

        這兩個是完全等價的。除了當我們運行循環版本時,我們得到了一個我們不太想要的信息:

        python test_primes.py
        ...F
        ======================================================================
        FAIL: test_negative_number (__main__.PrimesTestCase)
        Is a negative number correctly determined not to be prime?
        ----------------------------------------------------------------------
        Traceback (most recent call last):
        File "test_primes.py", line 22, in test_negative_number
         self.assertFalse(is_prime(index))
        AssertionError: True is not false
         
        ----------------------------------------------------------------------
        Ran 4 tests in 0.000s
         
        FAILED (failures=1)
        
        

        嗯···我們知道測試失敗了,但是是在哪個負數上失敗的?非常沒用的是,Python的單元測試框架并沒有打印出預期值和實際值。我們可以移步到兩種方式上,并用其中之一來解決問題:通過msg參數,或通過使用一個第三方的單元測試框架。

        使用msg參數來assertFalse僅僅能夠使我們認識到我們可以用字符串的格式設置來解決問題。

        def test_negative_number(self):
         """Is a negative number correctly determined not to be prime?"""
         for index in range(-1, -10, -1):
         self.assertFalse(is_prime(index), msg='{} should not be determined to be prime'.format(index))
        

        從而給出了如下輸出信息:

        python test_primes
        ...F
        ======================================================================
        FAIL: test_negative_number (test_primes.PrimesTestCase)
        Is a negative number correctly determined not to be prime?
        ----------------------------------------------------------------------
        Traceback (most recent call last):
        File "./test_primes.py", line 22, in test_negative_number
         self.assertFalse(is_prime(index), msg='{} should not be determined to be prime'.format(index))
        AssertionError: True is not false : -1 should not be determined to be prime
         
        ----------------------------------------------------------------------
        Ran 4 tests in 0.000s
         
        FAILED (failures=1)
        

        妥善地修復代碼

        我們看到,失敗的負數是第一個數字:-1。為了解決這個問題,我們可以為負數增再增加一個特殊檢查,但是編寫單元測試的目的不是盲目的添加代碼來檢測邊界情況。當一個測試失敗時,我們應該退后一步并且確定解決問題的最佳方式。在這種情況下,我們就不該增加一個額外的if:

        def is_prime(number):
         """Return True if *number* is prime."""
         if number < 0:
         return False
         
         if number in (0, 1):
         return False
         
         for element in range(2, number):
         if number % element == 0:
         return False
         
         return True
        

        應當首先使用如下代碼:

        def is_prime(number):
         """Return True if *number* is prime."""
         if number <= 1:
         return False
         
         for element in range(2, number):
         if number % element == 0:
         return False
         
         return True
        

        在后一個代碼中,我們發現如果參數小于等于1時,兩個if語句可以合并到一個返回值為false的語句中。這樣做不僅更加簡潔,并且很好的貼合了素數的定義(一個比1大并且只能被1和它本身整除的數)。

        第三方測試框架

        我們本來也可以通過使用第三方測試框架解決這個由于信息太少導致測試失敗的問題。最常用的兩個是py.test和nose。通過運行語句py.test -l(-l為顯示局部變量的值)可以得到如下結果。

        #! bash
         
        py.test -l test_primes.py
        ============================= test session starts ==============================
        platform linux2 -- Python 2.7.6 -- pytest-2.4.2
        collected 4 items
         
        test_primes.py ...F
         
        =================================== FAILURES ===================================
        _____________________ PrimesTestCase.test_negative_number ______________________
         
        self = 
         
         def test_negative_number(self):
         """Is a negative number correctly determined not to be prime?"""
         for index in range(-1, -10, -1):
        > self.assertFalse(is_prime(index))
        E AssertionError: True is not false
         
        index = -1
        self = 
         
        test_primes.py:22: AssertionError
        

        正如你所看到的,一些更有用的信息。這些框架提供了比單純的更詳細的輸出更多的功能,但問題是僅僅知道它們能存在和擴展內置unittest測試包的功能。

        結束語

        在這篇文章中,你學到了什么是單元測試,為什么它們如此重要,還有怎樣編寫測試。這就是說,要注意我們只是剖開了測試方法學中的表層,更多高級的話題,比如測試案例的組織、持續整合以及測試案例的管理等都是可供那些想要進一步學習Python中的測試的讀者研究的很好的話題。

      1. 在不改變其功能的前提下重組/清理代碼
      2. 編代碼時不暴露其內部數據或函數并且不使用其他代碼的內部數據或函數
      3. 聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        在Python編程過程中用單元測試法調試代碼的介紹

        在Python編程過程中用單元測試法調試代碼的介紹:對于程序開發新手來說,一個最常見的困惑是測試的主題。他們隱約覺得單元測試是很好的,而且他們也應該做單元測試。但他們卻不懂這個詞的真正含義。如果這聽起來像是在說你,不要怕!在這篇文章中,我將介紹什么是單元測試,為什么它有用,以及如何對Pyt
        推薦度:
        標簽: 編程 python debug
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 香蕉视频在线观看免费国产婷婷 | 亚洲午夜无码久久| 无码少妇精品一区二区免费动态| 亚洲一区二区视频在线观看| 免费视频精品一区二区| 亚洲成A人片在线观看无码3D | 中文字幕久无码免费久久| 亚洲精品视频免费观看| 一区视频免费观看| 日韩一卡2卡3卡4卡新区亚洲| 91麻豆国产免费观看| 无码久久精品国产亚洲Av影片 | 天堂亚洲国产中文在线| 国产乱码免费卡1卡二卡3卡| 久久亚洲国产最新网站| 免费国产怡红院在线观看| 伊人久久国产免费观看视频| 久久久久久久尹人综合网亚洲| 精品在线免费观看| 亚洲色成人网一二三区| 国产高潮流白浆喷水免费A片 | 亚洲色欲久久久综合网| 久久久久久精品成人免费图片| 国产成人亚洲综合网站不卡| 免费国产高清视频| a级毛片毛片免费观看久潮| www.91亚洲| 久久免费高清视频| 国产精品亚洲片夜色在线| 国产精品成人四虎免费视频| 2017亚洲男人天堂一| 国产一精品一aⅴ一免费| 在线视频网址免费播放| 亚洲男人电影天堂| 久久久久成人片免费观看蜜芽| 91亚洲国产成人久久精品网站| 搡女人真爽免费视频大全| 精品国产免费一区二区三区| 亚洲成人黄色网址| 亚洲无码黄色网址| 日韩免费精品视频|