Python 單元測試(unittest)的使用小結

2022-01-05 軟體測試unittest

Python中有一個自帶的單元測試框架是unittest模塊,用它來做單元測試,本篇文章主要介紹了Python 單元測試(unittest)的使用小結,具有一定的參考價值,感興趣的小夥伴們可以參考一下

測試目錄

項目的整體結構可以參考「軟體目錄開發規範」,這裡單說測試目錄。一般都是在項目裡單獨創建一個測試目錄,目錄名就是「tests」。

關於目錄的位置,一種建議是,在項目名(假設項目名是Foo)的一級子目錄下創建二級子目錄 「Foo/foo/tests」 。但是這樣可能是因為用起來不方便,有很多是按下面的做法。不過下面的示例我還是用這個方法來創建測試目錄。
還可以把測試目錄向上移一層,作為一級子目錄,直接創建在項目之下 「Foo/tests」。參考django、scrapy、flask都是這樣的做法。

測試函數

標題的意思是對函數(def)進行測試,相對於測試類(class)。

學習測試,得有要測試的代碼。下面是一個簡單的函數,接收城市名和國家名,返回一個格式為「City, Country「這樣的字符串:

def get_city_info(city, country):  city_info = "%s, %s" % (city, country)  return city_info.title()

接下來就對上面的這個函數進行測試。

手動測試

現在來寫一個使用這個函數的程序:

try:  from unit_test.utils.city_functions import get_city_infoexcept ModuleNotFoundError:  import sys  sys.path.append('../..')  from unit_test.utils.city_functions import get_city_info print("Enter 'q' at any time to quit.")while True:  city = input("city name: ")  if city == 'q':    break  country = input("country name: ")  if country == 'q':    break  fullname = get_city_info(city, country)  print("\tcity info:", fullname)

然後運行的結果:

Enter 'q' at any time to quit.
city name: shanghai
country name: china
    city info: Shanghai, China
city name: q

Process finished with exit code 0

上面這樣是手動測試,還是得有一種自動測試函數輸出的高效方式。如果能夠對get_fullname()進行自動測試,就能始終確信,給這個函數提供測試過的姓名後,它能返回正確的結果。尤其是在對函數進行修改的前後。

模塊導入路徑的問題

PyCharm會自動把項目目錄加到環境變量裡去,在PyCharm裡執行都沒問題。但是如果不用PyCharm而是單獨運行,這個目錄結構應該會有點問題,會找不到需要測試的函數。簡單點就是把測試用例和被測試的函數放到同一個目錄裡,然後改一下 from import 就可以正常運行了。或者自己手動添加環境變量,就像例子裡那樣。

單元測試-unittest

Python標準庫中的模塊unittest提供了代碼測試工具。

創建測試用例

為函數編寫測試用例,可先導入模塊unittest以及要測試的函數,再創建一個繼承unittest.TestCase的類,並編寫一系列方法對函數行為的不同方面進行測試。

下面是一個只包含一個方法的測試用例:

import unittesttry:  from unit_test.utils.city_functions import get_city_infoexcept ModuleNotFoundError:  import sys  sys.path.append('../..')  from unit_test.utils.city_functions import get_city_info class CitiesTestCase(unittest.TestCase):  """測試city_functions.py"""  def test_city_country(self):    city_info = get_city_info('shanghai', 'china')    self.assertEqual(city_info, 'Shanghai, China')   def test_New_York(self):    city_info = get_city_info('new york', 'America')    self.assertEqual(city_info, 'New York, America') if __name__ == '__main__':  unittest.main()

命名的規則和建議:

在測試的方法的最後,使用了unittest類最有用的功能之一:一個斷言方法。來檢查得到的結果和我們預期的結果是否一致。

輸出的效果

最後一行 unittest.main() 讓Python運行這個文件中的測試。執行程序後得到如下的輸出:

.

Ran 1 test in 0.000s

OK

運行測試用例時,每完成一個單元測試,Python都列印一個字符:

測試通過時列印一個句點;

測試引發錯誤時列印一個E;

測試導致斷言失敗時列印一個F。

這就是你運行測試用例時,在輸出的第一行中看到的句點和字符數量各不相同的原因。如果測試用例包含很多單元測試,需要運行很長時間,就可通過觀察這些結果來獲悉有多少個測試通過了。

PyCharm對單元測試做了自己的優化,輸出看不到上面的點,而是有更加漂亮的展示方式。

測試不通過

現在看下測試不通過的效果。這裡不修改測試用例,而是對get_city_info()函數做一個update,現在還要顯示城市的人口數量:

def get_city_info(city, country, population):  city_info = "%s, %s - 人口: %d" % (city, country, population)  return city_info.title()

這次再執行測試用例,輸出如下:

E
======================================================================
ERROR: test_city_country (__main__.CitiesTestCase)

Traceback (most recent call last):
  File "test_city_functions.py", line 17, in test_city_country
    city_info = get_city_info('shanghai', 'china')
TypeError: get_city_info() missing 1 required positional argument: 'population'


Ran 1 test in 0.001s

FAILED (errors=1)

這裡看的是E而不是之前的點,表示有一個錯誤。

測試未通過的處理

這裡不要去修改之前的測試用例。假設update之前的函數已經在項目內使用起來了,現在測試不通過,表示之前調用這個函數的代碼都有問題。如果不想改項目裡其它的代碼,這裡先嘗試修改get_city_info()函數,讓它能夠通過測試,也可以加上新的功能:

def get_city_info(city, country, population=None):  if population:    city_info = "%s, %s - 人口: %d" % (city, country, population)  else:    city_info = "%s, %s" % (city, country)  return city_info.title()

現在的各個版本的update才是兼容舊版本的代碼,這次測試用例就可以通過了。

添加新測試

之前的測試用例只能驗證就的功能,現在添加了新功能,是否沒問題,還得通過測試來進行驗證:

class CitiesTestCase(unittest.TestCase):  """測試city_functions.py"""  def test_city_country(self):    city_info = get_city_info('shanghai', 'china')    self.assertEqual(city_info, 'Shanghai, China')   def test_New_York_population(self):    city_info = get_city_info('new york', 'America', 8537673)    self.assertEqual(city_info, 'New York, America - 人口: 8537673')

現在新功能的測試用例也用了,並且2個測試都能通過。以後如果還需要對get_city_info()函數進行修改,只要再運行測試就可以知道新的代碼是否會對原有的項目有影響。

斷言方法

模塊在unittest.TestCase類中提供了很多斷言方法,之前已經用一個了。下面是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 CourseManage(object):   def __init__(self, course):    self.course = course    self.students = []   def show_course(self):    print("課程:", self.course)   def add_student(self, name):    self.students.append(name)   def show_students(self):    print("所有學員:")    for student in self.students:      print('-', student)

為證明CourseManage類工作正常,再編寫一個使用它的程序:

from unit_test.course import CourseManage course = CourseManage("Python")course.show_course()print("準備錄入學員...")print("Enter 'q' at any time to quit.\n")while True:  resp = input("Student's Name: ")  if resp == 'q':    break  if resp:    course.add_student(resp.title())print("\n錄入完畢...")course.show_students()

這段程序定義了一門課程,並使用課程名創建了一個CourseManage對象。接下來主要就是調用對象的add_student()方法來錄入學員名字。輸入完畢後,按q能退出。最後會列印所有的學員。
所有的輸入和輸出如下:

課程: Python
準備錄入學員...
Enter 'q' at any time to quit.

Student's Name: oliver queen
Student's Name: barry allen
Student's Name: kara
Student's Name: sara lance
Student's Name: q

錄入完畢...
所有學員:
- Oliver Queen
- Barry Allen
- Kara
- Sara Lance

Process finished with exit code 0

編寫類的測試用例

下面來編寫一個測試,對CourseManage類的行為的一個方面進行驗證。如果用戶輸入了某個學員的名字,這個名字可以被存儲在self.students的列表裡。所以,需要做的是在學員被錄入後,使用assertIn()這個斷言方法:

import unittestfrom unit_test.course import CourseManage class TestCourseManage(unittest.TestCase):   def test_add_student(self):    course = CourseManage("Python")    name = 'snart'    course.add_student(name.title())    self.assertIn('Snart', course.students) if __name__ == '__main__':  unittest.main()

上面的方法只驗證了錄入一個學員的情況,而大多數情況下都是有很多學員的。所以,還要添加一個方法,驗證錄入多個學員是否正常:

class TestCourseManage(unittest.TestCase):   def test_add_student(self):    course = CourseManage("Python")    name = 'snart'    course.add_student(name.title())    self.assertIn('Snart', course.students)   def test_add_students(self):    course = CourseManage("Python")    name_list = ['oliver queen', 'barry allen', 'kara', 'sara lance']    for name in name_list:      course.add_student(name.title())    for name in name_list:      self.assertIn(name.title(), course.students)

setUp() 方法

在上面的例子裡,每個測試方法中都創建了一個實例。但是還有一種需求是,我希望只創建一個實例,但是要在多個方法裡對這個實例進行操作來反覆驗證。在unittest.TestCase類包含方法setUp(),就可以只實例化一次,並可以在每個測試方法中使用。如果在TestCase類中包含了方法setUp(),Python會先運行它,再運行各個以test_打頭的方法。
簡單點說,setUp()方法就是在父類裡預留的一個鉤子,會在其他測試方法運行前先運行:

import unittestfrom unit_test.course import CourseManage class TestCourseManage(unittest.TestCase):   def setUp(self):    self.course = CourseManage("Python")    self.name_list = ['oliver queen', 'barry allen', 'kara', 'sara lance']   def test_add_student(self):    name = 'snart'    self.course.add_student(name.title())    self.assertIn('Snart', self.course.students)   def test_add_students(self):    for name in self.name_list:      self.course.add_student(name.title())    for name in self.name_list:      self.assertIn(name.title(), self.course.students) if __name__ == '__main__':  unittest.main()

測試自己編寫的類時,使用setUp()方法會讓測試方法編寫起來更容易,下面是建議的做法:

在setUp()方法中創建一系列實例並設置它們的屬性,再在測試方法中直接使用這些實例。相比於在每個測試方法中都創建實例並設置其屬性,這要容易得多。

小結

如果你在項目中包含了初步測試,其他程式設計師將更敬佩你,他們將能夠更得心應手地嘗試使用你編寫的代碼,也更願意與你合作開發項目。如果你要跟其他程式設計師開發的項目共享代碼,就必須證明你編寫的代碼通過了既有測試,通常還需要為你添加的新行為編寫測試。

請通過多開展測試來熟悉代碼測試過程。對於自己編寫的函數和類,請編寫針對其重要行為的測試,但在項目早期,不要試圖去編寫全覆蓋的測試用例,除非有充分的理由這樣做。

pytest

這篇講的是Python內置的單元測試模塊。作為初學者先用著熟悉起來就很不錯了。

pytest是Python最流程的單測框架之一。具體可以上GitHub參考下那些開源項目的單元測試,很多用的是這個。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持公眾號「軟體測試unittest」。

您可能感興趣的文章:

Python單元測試框架unittest簡明使用實例

Python  unittest單元測試框架的使用

Python unittest 簡單實現參數化的方法

Pytest如何使用skip跳過執行測試

Python Django框架單元測試之文件上傳測試示例

Python單元測試與測試用例簡析

Python單元測試模塊doctest的具體使用

Python unittest單元測試框架及斷言方法

Python unittest單元測試框架實現參數化

Python編寫單元測試代碼實例

全面介紹python中很常用的單元測試框架unitest

Python+unittest+requests+excel實現接口自動化測試框架

基於Python的接口自動化unittest測試框架和ddt數據驅動詳解

Python單元測試框架unittest使用方法講解

python單元測試unittest實例詳解

Python中unittest用法實例

Python+request+unittest實現接口測試框架集成實例

python中如何打包用戶自定義模塊

詳解Python yaml模塊

python用Configobj模塊讀取配置文件

Python中fnmatch模塊的使用詳情

Python unittest裝飾器實現原理及代碼

對python的unittest架構公共參數token提取方法詳解

Python單元測試工具doctest和unittest詳細使用解析

Python + Requests + Unittest接口自動化測試實例分析

python pytest進階之fixture詳解

python pytest進階之conftest.py詳解

pytest之assert斷言的具體使用

Pytest接口自動化測試框架搭建模板

Python基於Hypothesis高級測試庫生成測試數據

pytest配置文件pytest.ini的詳細使用

Pytest中skip和skipif的具體使用方法

python中pytest收集用例規則與運行指定用例詳解

python pytest進階之xunit fixture詳解

python使用pytest接口自動化測試的使用

python單元測試之pytest的使用

pytest基本用法簡介

pycharm中使用request和Pytest進行接口測試的方法

通過代碼實例解析Pytest運行流程

pycharm不以pytest方式運行,想要切換回普通模式運行的操作

在pycharm中文件取消用 pytest模式打開的操作

Pytest單元測試框架如何實現參數化

Python 測試框架unittest和pytest的優劣

python單元測試框架pytest的使用示例

Python測試框架:pytest學習筆記

詳解如何使用Pytest進行自動化測試

Pytest測試框架基本使用方法詳解

測試入門以及pytest入門

Python測試框架之pytest詳解

刷完500道高頻面試題,我能去面試大廠了嗎?(持續更新)

今天也要點一鍵哦❤️❤️

  "贊"、"在看"、

相關焦點

  • unittest框架及requests庫問題小結及總結
    封裝是為了更好的調用,更好的實現測試腳本與數據的分離,利於後續的維護。因為接口測試數據,經常性會變更,不變的是請求體中的參數名稱,變化的是參數的值。那麼,我們封裝後,把參數的值統一保存,這樣,我們測試的時候,就可以調用不同的參數來實現了。
  • Python+selenium教程
    人工智慧機器學習方面應用,python有很多庫很方便做人工智慧,比如numpy, scipy做數值計算的,sklearn做機器學習的,pybrain做神經網絡的。軟體測試領域,自動化測試(Web端(python+selenium)和移動客戶端python+appium)Python2.X 與Python3.X學哪個?
  • Pytest丨如何使用全功能的Python測試框架?小白必看
    關注我,每周分享軟體測試技術乾貨、面試經驗,想要進入軟體測試學習交流群的可以直接私信我哦~~我們在寫自動化的過程中,用例的斷言也是至關重要的,斷言可以幫助我們判斷用例測試點是否成功和失敗。當然在我們這麼強大的pytest框架中,斷言也是比較強大的。為什麼?繼續往下看。
  • 在 Windows上寫 Python 代碼的最佳組合!
    下面我們從最初的安裝、環境管理到編寫、測試、發布代碼,介紹我們該如何優雅地使用 VS Code。在任何平臺上都可以安裝 Visual Studio Code。官網提供了 Windows、Mac 和 Linux 的完整安裝說明,並且會每月更新編輯器,其中包含新功能和錯誤修正。
  • Python 最強編輯器詳細使用指南!
    不經單元測試的應用都不可靠。PyCharm 可以幫助你快速舒適地寫單元測試並運行。默認情況下,unittest 被用作測試運行器,而 PyCharm 還支持其他測試框架,如 pytest、nose、doctest、tox 和 trial。例如,你可以按照以下步驟為項目選擇 pytest 測試運行器:打開 Settings/Preferences → Tools → Python Integrated Tools 設置對話框。
  • 在Win上做Python開發?當然是用官方的MS Terminal和VS Code了
    Python 擴展使用戶可以在 Visual Studio Code 中進行 Python 開發,具有以下特徵:既支持 Python 3.4 及更高版本,也支持 Python 2.7 版本使用 IntelliSense 完成代碼補全Linting調試支持代碼片段支持單元測試支持自動使用 conda 和虛擬環境在 Jupyter 環境和 Jupyter 筆記本中進行代碼編輯
  • Python最強IDE之Pycharm詳細使用指南!
    不經單元測試的應用都不可靠。PyCharm 可以幫助你快速舒適地寫單元測試並運行。默認情況下,unittest 被用作測試運行器,而 PyCharm 還支持其他測試框架,如 pytest、nose、doctest、tox 和 trial。例如,你可以按照以下步驟為項目選擇 pytest 測試運行器:打開 Settings/Preferences → Tools → Python Integrated Tools 設置對話框。
  • 來自Java程式設計師的Python新手入門小結
    小結三種包裹方式:列表方括號,元組圓括號,字典和集合大括號(字典的元素是鍵值對,集合是單個元素),另外元組可以不包裹,有逗號就行set方法可以將列錶轉為集合:上述極簡的方式是不推薦使用的,因為缺少了namespace隔離,在API的正確性上就缺少了保障關於自己的模塊假設有一個python文件hello.py,內容如下,定義了名為doHello的方法,再執行一下試試:
  • python3 udp socket 測試及包長解析
    工具:python : v3.7.6wireshark :v3.2.2Server code:
  • 單元測試可測試程式設計師代碼編寫的正確性,如何使用VS2019測試項目
    在Visual Studio 2019中內置了多種測試工具,這裡我們使用基於.NET Framework的單元測試項目來測試代碼。單元測試是以項目的方式存在的,與應用程式項目結合在一起對代碼進行單元測試,保證每開發一個方法都是經過測試的合格程序。
  • python+ pycharm 環境安裝 + pycharm使用
    一、下載和安裝python1.可以搜索python官網找到官方連結點擊進入2.也可以用以下連結點擊進入:https://www.python.org/3.進入python後把滑鼠移到downloads上,然後看到下拉選項
  • Python常用庫大全
    IPython – 功能豐富的工具,非常有效的使用交互式 Python。 bpython- 界面豐富的 Python 解析器。 ptpython – 高級交互式Python解析器, 構建於python-prompt-toolkit 之上。 文件文件管理和 MIME(多用途的網際郵件擴充協議)類型檢測。
  • Visual Studio Code 8 月 Python 擴展更新
    Jupyter Notebook 單元調試此版本正式發布了 Jupyter Notebook 單元調試功能(cell debug),使用該功能,開發者可以設置斷點並單擊單元格定義中顯示的「調試單元」選項。這將啟動一個調試會話,用於代碼跟進、檢查變量並設置監控,與調試 Python 文件或應用類似。
  • Python接口測試實戰丨如何實現特殊字符集的自動化測試?
    在當前網際網路產品更新迭代的快節奏下,回歸測試的時間被嚴重壓縮,在金融領域和其他網際網路應用場景下,支付、轉帳、清算往往是核心功能,為了確保資金安全和快速到帳,接口在對用戶名、帳戶名中的特殊字符的正確處理顯得尤為重要。
  • 系統測試:單元測試相關知識筆記
    一、單元測試概念單元測試也成為模塊測試,在模塊編寫完成且五編譯錯誤後就可以進行。單元測試側重模塊中的內部處理邏輯和數據結構。如果採用機器測試,一般用白盒測試法。二、單元測試檢查模塊特徵1、模塊接口模塊接口保證了測試模塊數據流可以正確地流入、流出。主要檢查一下要點:測試模塊輸入參數和形式參數在個數、屬性、單位是否一致。
  • 慢步python,你苦苦找尋的python中文使用手冊在哪裡?這裡有答案
    #學習難度大python對大家來說,應該算是相對新的程式語言。即使這樣,我們學習python的道路依舊困難重重。問題在,相關的學習資料不夠系統。初學者使用手冊像以前剛開始使用電視、手機一樣,都有一本使用說明書,即使用手冊。
  • Python使用技巧最終篇(乾貨收藏)
    怎麼才算精通python熟悉語法以及原聲數據結構熟悉基本實現中的性能特點,就是知道什麼操作會慢會使用profile以及基於profile的性能分析工具會使用運行時編譯和靜態編譯的工具。>python裡有一個很奇妙的monkey patch,中文叫做猴子補丁,是指的是在運行時動態替換某些已加載的模塊的實現。