# 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
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.