如何在Python中創建mock

2021-03-02 CSDN

【編者按】mock是一門技術,通過偽造部分實際代碼,從而讓開發者可以驗證剩餘代碼的正確性。從而,通過mock,開發者可以非常便捷地測試某個函數的內部代碼,下面就帶你穿梭mock。

關於譯者:曾靈敏,OneAPM工程師,偶然的機會接觸到Python,為其簡潔優雅的語法所吸引,並毅然投身其中,目前在OneAPM從事Python探針研發工作。

以下為譯文


本博文主要聚焦mock的使用。mock是一門技術,通過偽造部分實際代碼,從而讓開發者可以驗證剩餘代碼的正確性。下面將通過幾個簡單的示例演示mock在Python測試代碼中的使用,以及這項極其有用的技術是如何幫助開發者改善測試代碼的。

為什麼使用mock

當進行單元測試時,目標往往是為了測試非常小的代碼塊,例如一個獨立存在的函數或類方法。換句話說,代碼測試只針對指定函數的內部代碼。如果測試代碼需要依賴於其他的代碼片段,在某種不幸的情形下,即使被測試的函數沒有變化,這部分內嵌代碼的修改仍然可能破壞原有的測試。看看下面的例子,你將豁然開朗:

[py] view plaincopy

# function.py

def add_and_multiply(x, y):

addition = x + y

multiple = multiply(x, y)

return (addition, multiple)

def multiply(x, y):

return x * y

# test.py

import unittest

class MyTestCase(unittest.TestCase):

def test_add_and_multiply(self):

x = 3

y = 5

addition, multiple = add_and_multiply(x, y)

self.assertEqual(8, addition)

self.assertEqual(15, multiple)

if __name__ == "__main__":

unittest.main()

[py] view plaincopy

$ python test.py

.

Ran 1 test in 0.001s

OK

在上面的例子中,`add_and_multiply`計算兩個數的和與乘積並返回。「add_and_multiply」調用了另一個函數「multiply」進行乘積計算。如果期望摒棄「傳統「的數學,並重新定義「multiply」函數,在原有的乘積結果上加3。新的「multiply」函數如下:

[py] view plaincopy

def multiply(x, y): return x * y + 3

現在就會遇到一個問題。即使測試代碼沒有變化,需要測試的函數也沒有變化,然而,「test_add_and_multiply」卻會執行失敗:

[py] view plaincopy

$ python test.py F ======================================================================

FAIL: test_add_and_multiply (__main__.MyTestCase)

Traceback (most recent call last): File "test.py", line 13, in test_add_and_multiply

self.assertEqual(15, multiple) AssertionError: 15 != 18

Ran 1 test in 0.001s FAILED (failures=1)

這個問題之所以會發生,是因為原始測試代碼並非真正的單元測試。儘管開發者期望測試的是外部函數,但往往隱性地將內部函數也包含進來,因期望結果是依賴於這個內部函數的行為的。雖然在上面這個簡單的示例中呈現的差異顯得毫無意義,但某些場景下,我們需要測試一個複雜的邏輯代碼塊,例如,一個Django視圖函數基於某些特定條件調用各種不同的內部功能,從函數調用結果中分離出視圖邏輯的測試就顯得尤為重要了。

解決這個問題有兩種方案。要麼忽略,像集成測試那樣去進行單元測試,要麼求助於mock。第一種方案的缺點是,集成測試僅僅告訴我們函數調用時哪一行代碼出問題了,這樣很難找到問題根源所在。這並不是說,集成測試沒有用處,因為在某些情況下它確實非常有用。不管怎樣,單元測試和集成測試用於解決不同的問題,它們應該被同時使用。因此,如果想要成為一個好的測試人員,mock是一個不錯的替代選擇。

mock是什麼

mock是一個極其優秀的Python包,Python 3已將其納入標準庫。對於我們這些還在UnicodeError遍布的Python 2.x中掙扎的苦逼碼農,可以通過pip進行安裝:

[py] view plaincopy

pip install mock==1.0.1

mock有多種不同的用法。我們可以用它提供猴子補丁功能,創建偽造的對象,甚至可以作為一個上下文管理器。所有這些都是基於一個共同目標的,用副本替換部分代碼來收集信息並返回偽造的響應。

mock的[ 文檔]非常密集,尋找特定的用例信息可能會非常棘手。這裡,我們就來看看一個常見的場景——替換一個內嵌函數並檢查它的輸入和輸出。

開始mock之旅

下面將使用mock重新編寫單元測試。接下來,會討論發生了什麼,以及為什麼從測試的角度來看它是非常有用的:

[py] view plaincopy

# test.py

import mock

import unittest

class MyTestCase(unittest.TestCase):

@mock.patch('multiply')

def test_add_and_multiply(mock_multiply):

x = 3

y = 5

mock_multiply.return_value = 15

addition, multiple = add_and_multiply(x, y)

mock_multiply.assert_called_once_with(3, 5)

self.assertEqual(8, addition)

self.assertEqual(15, multiple)

if __name__ == "__main__":

unittest.main()

至此,我們可以改變「multiply」函數來做任何事情——它可能返回加3後的乘積,返回None,或返回favourite line from Monty Python and the Holy Grail——你會發現,我們上面的測試仍然可以通過。這是因為我們mock了「multiply」函數。在真正的單元測試場景下,我們並不關心「multiply」函數內部發生了什麼,從測試「add_and_multiply」的角度來看,只關心「multiply」被正確的參數調用了。這裡我們假定有另一個單元測試會針對「multiply」的內部邏輯進行測試。


實現過程

乍一看,上面的語法可能不好理解。下面逐行分析:

[py] view plaincopy

@mock.patch('multiply')

def test_add_and_multiply(mock_multiply):

使用「mock.patch」裝飾器來用mock對象替換"multiply'。然後將它作為一個參數"mock_multiply"插入到測試代碼中。在這個測試的上下文中,任何對「multiply」的調用都會被重定向到「mock_multiply」對象。

有人會質疑——「怎麼能用對象替換函數!」別擔心!在Python的世界,函數也是對象。通常情況下,當我們調用「multiply()」,實際執行的是「multiply」函數的「__call__」方法。然而,恰當的使用mock,對「multiply()」的調用將執行mock對象,而不是「__call__」方法。

[py] view plaincopy

mock_multiply.return_value = 15

為了使mock函數可以返回任何東西,我們需要定義其「return_value」屬性。實際上,當mock函數被調用時,它用於定義mock對象的返回值。

[py] view plaincopy

addition, multiple = add_and_multiply(x, y) mock_multiply.assert_called_once_with(3,

5)

在測試代碼中,我們調用了外部函數「add_and_multiply」。它會調用內嵌的`multiply`函數,如果我們正確的進行了mock,調用將會被定義的mock對象取代。為了驗證這一點,我們可以用到mock對象的高級特性——當它們被調用時,傳給它們的任何參數將被儲存起來。顧名思義,mock對象的「assert_called_once_with」方法就是一個不錯的捷徑來驗證某個對象是否被一組特定的參數調用過。如果被調用了,測試通過。反之,「assert_called_once_with」會拋出`AssertionError`的異常。

學到的知識

這裡會遇到很多實際問題。首先,我們通過mock將「multiply」函數從「add_and_multiply」中分離出來。這就意味著我們的單元測試只針對「add_and_multiply」的內部邏輯。只有針對「add_and_multiply」的代碼修改將影響測試的成功與否。

其次,可以控制內嵌函數的輸出,以確保外部函數處理了不同的情況。例如,「add_and_multiply」可能有邏輯條件依賴於「multiply」的返回值:比如說,我們只想在乘積大於10的條件下返回一個值。通過人為設定「multiply」的返回值,我們可以模擬乘積小於10的情況以及乘積大於10的情況,從而可以很容易測試我們的邏輯正確性。

最後,我們現在可以驗證被mock的函數被調用的次數,並傳入了正確的參數。由於我們的mock對象取代了「multiply」函數的位置,我們知道任何針對「multiply」函數的調用都會被重定向到該mock對象。當測試一個複雜的功能時,確保每一步都被正確調用將是一件非常令人欣慰的事情。

英文原文: Making a Mockery of Python

本文為CSDN原創,點擊「閱讀原文」可查看全文並參與討論。

如果您喜歡這篇文章,請點擊右上角「…」將本文分享給你的朋友。

相關焦點

  • python-mock的幾點使用記錄
    靜態方法靜態方法和模塊方法需要使用patch來mock1.在測試方法參數中得到Mock對象:以字符串的形式列出靜態方法的路徑,在測試的參數裡會自動得到一個Mock對象@patch('your.package.module.
  • 如何使用Visual Studio工具創建python項目
    隨著工具不斷完善,現在也可以進行python項目開發了。那麼,如何在Visual Studio 2019工具上創建python項目?操作步驟:1、通過快捷方式或電腦開始菜單,雙擊打開Visual Studio 2019工具
  • Python中如何創建和調用函數
    第八十五節:創建和調用函數一直以來,數學函數是我輩最大的緊箍咒,現在遇到Python中的函數,就這區區兩個字,竟然一度讓我有了退卻的念頭,鼓起勇氣學了一點點,感覺沒有那麼難,嗯,可以繼續,下面就把今天學習的一點心得分享給大家。不提數學函數了,直接說說Python中的函數的用途。
  • 如何在Visual Studio創建python文件並運行
    工具Visual Studiopython環境截圖工具技術python在Visual Studio開發工具中,創建python項目,根據項目的需要,新建不同的python文件;然後選擇python文件,進行運行。
  • 漫話:如何給女朋友解釋什麼是Mock?
    Mock,直譯過來的話是虛假的意思,但是在面向對象程序設計中,一般翻譯成模擬。如接口mock、mock對象等,通常表示接口模擬、模擬對象等。在軟體單元測試中,我們也需要用到這些測試對象。目的也類似,就是為了保證測試的全面性及準確性。之所以要在測試中使用Mock對象,其實有很多原因,其中最重要的原因就是真實對象的構造成本太高。這時候一般就會採用mock對象。
  • PostMan 之 Mock 接口測試
    你可以從 Postman 已有的測試集(Collection)中創建 Mock Server ,也可以直接創建 Mock Server(我們這裡選擇從已有的測試集中創建 Mock Server)。Mock server 詳細配置頁面,在此頁面中我們可以設置:Name the mock server命名 Mock Server。
  • python核心部分創建對象中各種名詞的定義及用法
    學了之前的基礎之後你會發現你基本上可以寫出很多小程序來了,包括用序列,字典,數字,字符串來創建函數,基本上可以完成你遇到的問題。但是python被稱為面向對象的語言,所以創建對象才是python的核心部分,我們今天就走進python的核心部分-創建對象。接下來幾天的章節非常重要非常核心,非常重要非常核心,非常重要非常核心,重要的事情說是三次。首先說一下幾個名詞的定義,方便你在以後的學習中理解。
  • 如何從Tensorflow中創建CNN,並在GPU上運行該模型(附代碼)
    在本教程中,您將學習卷積神經網絡(CNN)的架構,如何在Tensorflow中創建CNN,並為圖像標籤提供預測。
  • 從小白變高手,這7個超實用的Python自動化測試框架請收好!
    通過繼承unittest.TestCase來創建一個測試用例。舉個例:import unittestdef fun(x):return x + 1class MyTest(unittest.TestCase):def test(self):self.assertEqual(fun(3), 4)執行後成功。
  • Python開發:Win10創建定時任務執行Python腳本
    2020-12-26 07:48:50 來源: 小小追 舉報   日常開發過程中,
  • python:創建類和根據類創建實例
    1.餐館:創建一個名為Restaurant的類,其方法_init_()設置兩個屬性:restaurant_name和cuisine_type.創建一個名為describe_restaurant()的方法和一個名為open_restaurant()的方法,其中前者列印前述兩項信息
  • 前端 mock 完美解決方案實戰
    "login.logout": "success" 就返回login-mock.json中的login.success 的內容,配置沒有匹配到就請求轉發到後端服務。文件生成為了在build打包的時候把mock數據注入到前端代碼中去,使得mock.json文件內容儘可能的小,會根據conf.json的配置項來動態生成mock.json的內容,如果build裡面沒有開啟mock項,內容就會是一個空json數據。
  • 如何在python中引入高性能數據類型?
    作者|skura 來源|AI開發者 python 就像一件藝術珍藏品!python 最大的優點之一是它可以廣泛地選擇模塊和包。它們將 python 的功能擴展到許多流行的領域,包括機器學習、數據科學、web 開發、前端等等。其中最好的一個優點是 python 的內置 collections 模塊。
  • 如何在Visual Studio中創建excel並讀取數據
    >xlrd技術pythondjangoexcel在Visual Studio開發工具中,創建python項目,然後安裝xlwt和xlrd第三方庫,使用xlwt創建excel文件並寫入數據,使用xlrd讀取excel文件中的數據。
  • 7k Star 的 Python 測試框架入門指南
    最後要考慮的是如何讓 pytest 加載測試模塊。Pytest提供了不同的導入模式,具體取決於我們是否將測試放在了模塊(帶有__init__.py文件的文件夾)中,是否給測試文件定義了唯一名稱以及是否需要使用不同版本的Python來測試應用程式或庫。
  • python的requirements.txt的創建及使用
    python在中,可以使用requirements.txt記錄當前環境所使用的包及版本,以便其他系統中部署相同的環境。這裡介紹兩種常用python包管工具的創建和執行requirements.txt的方法pip方式:創建:(venv) $ pip freeze >requirements.txt
  • 使用MockMVC進行Controller單元測試
    這個測試套件就可以使用Spring-test庫中的MockMVC了。接下來,將以查詢接口為例,介紹如何對該接口進行單元測試。;import org.mockito.Mock;import org.mockito.Mockito;import org.mockito.MockitoAnnotations;import org.springframework.http.MediaType;import org.springframework.test.web.servlet.MockMvc
  • Python創建可以打開文件的EXE
    本文展示了一步步學習如何創建.exe程序的過程,最後做出我們想要的程序本文分為如下幾個內容生成最簡單的exe程序,只列印出一段字符串帶有參數的exe程序參數是文件名的情況真正實現改進方向生成最簡單的exe程序
  • 如何理解python中的類和對象?
    什麼是類和對象類和對象,在我們的生活中其實是很容易找例子的。類是一種把對象分組歸類的方法。比如動物,植物就可以看作是類,而大象,獅子就可以看作一個動物類中的對象;花,草可以看作是植物類中的對象。為什麼大象和獅子就劃分為動物類,花和草就劃分為植物類呢?
  • 前端mock完美解決方案實戰
    下面就說下我期望的前端mock要有哪些功能:生產打包可以把mock數據注入到打包的js中走前端mock對於後端已有的接口也能快速把Response數據轉化為mock數據對於第7點的作用是後續項目開發完成,在完全沒有開發後端服務的情況下,也可以進行演示。這對於一些ToB定製的項目來沉澱項目地圖(案例)很有作用。