Python基礎入門7--編寫測試用例

Python 基礎入門前六篇:php

這是第七篇,也是這個基礎入門系列的最後一篇內容,簡單介紹如何採用 unittest 模型編寫測試用例。java


測試函數

首先是給出用於測試的代碼,以下所示,這是一個接收姓和名而後返回整潔的姓名的函數:python

def get_formatted_name(first, last):
    full_name = first + ' ' + last
    return full_name.title()
複製代碼

簡單的測試代碼:c++

first = 'kobe'
last = 'bryant'
print(get_formatted_name(first, last)) # 輸出 Kobe Bryant
複製代碼

在 Python 標準庫中的模塊 unittest 提供了代碼測試工具。這裏介紹幾個名詞的含義:git

  • 單元測試:用於覈實函數的某個方面沒有問題;
  • 測試用例:一組單元測試,它們一塊兒覈實函數在各類情形下的行爲符合要求。
  • 全覆蓋式測試用例:包含一整套單元測試,涵蓋了各類可能的函數使用方式。

一般,最初只須要對函數的重要行爲編寫測試便可,等項目被普遍使用時才考慮全覆蓋。github

接下來就開始介紹如何採用 unittest 對代碼進行測試。正則表達式

首先是須要導入 unittest 模塊,而後建立一個繼承 unittest.TestCase 的類,並編寫一系列類方法對函數的不一樣行爲進行測試,以下代碼所示:算法

import unittest

class NamesTestCase(unittest.TestCase):
    ''' 測試生成名字函數的類 '''

    def test_first_last_name(self):
        formatted_name = get_formatted_name('kobe', 'bryant')
        self.assertEqual(formatted_name, 'Kobe Bryant')
        
unittest.main()
複製代碼

輸出結果以下,顯示運行的測試樣例是 1 個,耗時是 0.001s。編程

.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
複製代碼

上述是給了一個能夠經過的例子,而若是測試不經過,輸出是怎樣的呢,以下所示:bash

# 添加中間名
def get_formatted_name(first, middel, last):
    full_name = first + ' ' + middle + ' ' + last
    return full_name.title()

class NamesTestCase(unittest.TestCase):
    ''' 測試生成名字函數的類 '''
	# 不能經過的例子
    def test_first_name(self):
        formatted_name = get_formatted_name('kobe', 'bryant')
        self.assertEqual(formatted_name, 'Kobe Bryant')
                
unittest.main()
複製代碼

輸出結果以下,這裏會打印錯誤發生的地方和錯誤緣由:

E
======================================================================
ERROR: test_first_last_middle_name (__main__.NamesTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:/Python_Notes/Practise/unittest_practise.py", line 39, in test_first_last_middle_name
    formatted_name = get_formatted_name('kobe', 'bryant')
TypeError: get_formatted_name() missing 1 required positional argument: 'middle'

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)
複製代碼

很明顯是由於缺乏 middle 參數,若是但願經過測試,能夠將原函數進行以下修改:

def get_formatted_name(first, last, middle=''):
    ''' 接收姓和名而後返回完整的姓名 :param first: :param last: :return: '''
    if middle:
        full_name = first + ' ' + middle + ' ' + last
    else:
        full_name = first + ' ' + last
    return full_name.title()
複製代碼

而後添加新的測試方法,繼續運行,就能夠測試經過。

def test_first_last_middle_name(self):
    formatted_name = get_formatted_name('kobe', 'bryant', 'snake')
    self.assertEqual(formatted_name, 'Kobe Snake Bryant')
複製代碼

測試類

上一小節介紹了給函數寫測試的代碼,接下來介紹如何編寫針對類的測試。

斷言方法

unitest.TestCase 類中提供了不少斷言方法,上一小節就採用了 assertEqual 這一個判斷給定兩個參數是否相等的斷言方法,下面給出經常使用的 6 個斷言方法:

方法 用途
assertEqual(a, b) 覈實 a == b
assertNotEqual(a, b) 覈實 a != b
assertTrue(x) 覈實 x 是 True
assertFalse(x) 覈實 x 是 False
assertIn(item, list) 覈實 item 在 list 中
assertNotIn(item, list) 覈實 item 不在 list 中

這些方法都只能在繼承了 unittest.TestCase 的類中使用這些方法。

編寫針對類的測試

首先,編寫用於進行測試的類,代碼以下所示,這是一個用於管理匿名調查問卷答案的類:

class AnonymousSurvey():
    ''' 收集匿名調查問卷的答案 '''

    def __init__(self, question):
        ''' :param question: '''
        self.question = question
        self.responses = []
    
    def show_question(self):
        ''' 顯示問卷 :return: '''
        print(self.question)
    
    def store_response(self, new_response):
        ''' 存儲單份調查問卷 :param new_response: :return: '''
        self.responses.append(new_response)
    
    def show_results(self):
        ''' 顯示全部答卷 :return: '''
        print('Survey results:')
        for response in self.responses:
            print('- ' + response)
   
複製代碼

這個類包含三個方法,分別是顯示問題、存儲單份問卷以及展現全部調查問卷,下面是一個使用例子:

def use_anonymous_survey():
    question = "世上最好的語言是?"
    language_survey = AnonymousSurvey(question)
    # 顯示問題
    language_survey.show_question()
    # 添加問卷
    language_survey.store_response('php')
    language_survey.store_response('python')
    language_survey.store_response('c++')
    language_survey.store_response('java')
    language_survey.store_response('go')
    # 展現全部問卷
    language_survey.show_results()


if __name__ == '__main__':
    use_anonymous_survey()
複製代碼

輸出結果以下:

世上最好的語言是?
Survey results:
- php
- python
- c++
- java
- go
複製代碼

而後就開始編寫對該類的測試代碼,一樣建立一個類,繼承 unittest.TestCase ,而後類方法進行測試,代碼以下所示:

import unittest

class TestAnonmyousSurvey(unittest.TestCase):

    def test_store_single_response(self):
        ''' 測試保存單份問卷的方法 :return: '''
        question = "世上最好的語言是?"
        language_survey = AnonymousSurvey(question)
        language_survey.store_response('php')

        self.assertIn('php', language_survey.responses)
unittest.main()
複製代碼

上述代碼採用了 assertIn 斷言方法來測試函數 store_response()

這裏還能夠繼續測試可否存儲更多的問卷,以下所示,測試存儲三份問卷:

def test_store_three_response(self):
     question = "世上最好的語言是?"
     language_survey = AnonymousSurvey(question)
     responses = ['c++', 'php', 'python']
     for response in responses:
     	language_survey.store_response(response)

    for response in responses:
    	self.assertIn(response, language_survey.responses)
複製代碼

最後,在 unittest.TestCase 中其實包含一個方法 setUp() ,它的做用相似類的初始化方法 __init()__,它會在各類以 test_ 開頭的方法運行前先運行,因此能夠在這個方法裏建立對象,避免在每一個測試方法都須要建立一遍,因此上述代碼能夠修改成:

class TestAnonmyousSurvey(unittest.TestCase):

    def setUp(self):
        ''' 建立一個調查對象和一組答案 :return: '''
        question = "世上最好的語言是?"
        self.language_survey = AnonymousSurvey(question)
        self.responses = ['c++', 'php', 'python']

    def test_store_single_response(self):
        ''' 測試保存單份問卷的方法 :return: '''
        self.language_survey.store_response(self.responses[1])

        self.assertIn('php', self.language_survey.responses)

    def test_store_three_response(self):
        for response in self.responses:
            self.language_survey.store_response(response)

        for response in self.responses:
            self.assertIn(response, self.language_survey.responses)

複製代碼

運行後,輸出結果以下:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
複製代碼

注意,這裏運行成功,打印一個句號,由於是運行兩個測試方法成功,因此打印了兩個句號;若是運行出錯,打印一個 E ;測試致使斷言失敗,打印一個 F


參考

  • 《Python編程--從入門到實踐》

小結

Python 的基礎入門系列就介紹到這裏,最初第一篇初步制定的計劃是以下所示:

  1. 簡介和環境配置
  2. 變量和簡單的數據類型
  3. 列表和元組
  4. 字典
  5. if 條件語句
  6. for / while循環語句
  7. 函數
  8. 文件和異常
  9. 測試代碼

恰好基本都介紹上述 10 個方面的知識,後續還會有進階的知識點,包括函數和類的高級知識點,正則表達式,網絡編程方面的如進程和線程知識,固然還會總結或者翻譯一些不錯的介紹 Python 技巧的文章,以及一些經常使用庫的使用方法,好比 numpy、pandas、matplotlib 等等。

固然,還有就是努力作一些有趣的項目。

本文的代碼例子也都上傳到個人 Github 上:

歡迎關注個人微信公衆號--算法猿的成長,或者掃描下方的二維碼,你們一塊兒交流,學習和進步!

相關文章
相關標籤/搜索