# The introduction of Pytest-mock ###### tags: `unit-test` `pytest` `mock` ## 引言 pytest-mock是一個基於python自帶的unittest.mock所做的包裝,可以讓我們使用pytest撰寫測試時能更容易調用mock。 其除了能在測試結束時自動將mock關閉,也同時提供例如spy / stub等功能。 ## 用法 在pytest的測試中,只要調用`mocker`就能在測試中使用mock的功能,基本上調用的Api會跟unittest.mock是一樣的,範例如下: ```python= # in test_file.py def simple_dummy(): return 5 def test_dummy(mocker): mocker.patch("test_file.simple_dummy", return_value=10) output = simple_dummy() assert output == 10 ``` 注意,如同前篇文章[Mock, Patch and Namespace](https://hackmd.io/nwisog-lTfeseJq45Oa7aQ)所述,這裡需要注意patch調用的namespace等問題。 基本上,常用的mock method都會被pytest-mock支援,詳細支援項目可以參照文件 https://pytest-mock.readthedocs.io/en/latest/usage.html 同時,pytest-mock也可以在別的fixture中使用,但必須注意,如果該fixture有設定`scope`的話 ([pytest fixture的分級(scope)](https://hackmd.io/etnmI64GTRCjxzS60fiO7g)) 必須使用對應的mocker,例如: ```python= # still in test_file.py def simple_dummy(): return 5 @pytest.fixture(scope="session") def open_db(session_mocker): # we want to mock something here... session_mocker.patch("test_file.simple_dummy", return_value=10) # open db yield # close it ``` ## 特點 那麼,為什麼要使用這個套件呢? 如果各位使用過unittest.mock的話,會知道文件中推薦patch的方法分別是使用: * decorator * context manager 但在pytest的情境中,使用上述兩者會有兩個主要的問題: 1. 有多個patch需要存在同個測試項中,太多`with`造成程式難以閱讀 ```python= import mock def test_unix_fs(): with mock.patch('os.remove'): # ... with mock.patch('os.listdir'): # ... with mock.patch('shutil.copy'): # ... ``` 2. 如果使用decorator的方式,在test function的輸入param中會跟pytest本身的fixture參雜在一起,如以下範例中的fixture `db` ```python= import unittest from unittest.mock import patch import math_operations # give simple add / sub # assume we have a fixture called "db" @patch('math_operations.add', return_value=10) @patch('math_operations.subtract', return_value=5) def test_multiple_patches(mock_subtract, mock_add, db): result_add = math_operations.add(3, 2) result_subtract = math_operations.subtract(8, 3) assert result_add == 10 # Mocked return value from 'add' assert result_subtract == 5 # Mocked return value from 'subtract' ``` 在pytest-mock中,為了避免上述問題,使用了`mocker`這個fixture,把所有mock直接整併進測試項中,避免decorator造成的混亂,同時由於其會在單個測試項結束後將mock的項目關閉,所以也能避免必須要在測試項中使用`with`控制mock生效時限造成的撰寫與閱讀困難。 若真的需要在測試途中關閉某個mock,也可以使用`mocker.stop` 或 `mocker.stopall` ## 結語 通過以上簡單(?)的介紹,希望各位能理解使用pytest-mock的優勢,其可以避免複雜的情境造成必須撰寫難以閱讀的程式碼,同時也與pytest本身有良好的整合,方便各位更快速的撰寫測試。 那麼最後,希望各位的測試碼都能撰寫的簡潔易懂。 下次見搂~
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up