# mock, patch 與 namespace
###### tags: `unit-test`
## 引言
如果你曾經用過unittest.mock.patch,不知道在使用時你有沒有一個疑問:
我這個patch用下去,究竟要patch哪裡?
~~我是誰,我在哪裡~~
## 案例
如果今天我們的資料夾結構長這樣
```
root/
----app/
----connection.py
----test/
----test_connection.py
```
在connection.py內,是一個簡單的request
```python=
# connection.py in ./app
import requests
def connection():
# try to call a website
# default it return 200
response = requests.get('https://www.google.com.tw/')
return response.status_code
```
然後今天在測試的時候,如果是使用mock.patch不久的人,應該會有個顯著的疑惑
```python=
# test_connection.py
from app import connection
def test_connection(mocker):
# create mock object
mock_response = mocker.Mock()
mock_response.status_code = 200
# patch requests
mock_requests = mocker.patch("app.connection.requests")
mock_requests.get.return_value = mock_response
# act
response = connection.connection()
assert response == 200
```
在寫到第11行的時候,到底patch要指到哪裡才是對的呢?
究竟是patch
1. "app.connection.requests"
2. "app.connection.requests.get"
3. "requests"
4. "requests.get"
究竟該patch誰才是對的?
如果在這個地方放棄思考,用try&error的方式硬幹當然是可以的,但沒有搞懂這裡的邏輯的話不說可惜,之後照寫的測試可能會怪怪的(汗
## Namespace
在揭曉答案之前,有個基本的東西需要知道
在各位import module的時候,有沒有想過import到底做了什麼呢?
例如一個簡單的範例,我們在A.py裡import
```python=
import requests
```
這時python會把requests的名子抓過來,放到這個A.py的namespace裡
這時候如果在這個A.py內呼叫
```python=
dir()
```
就會看到
```
['__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'requests']
```
requests現在就會被A.py看到了
## unittest.mock.patch
patch究竟做了什麼事情呢?
實際上的運作是,patch會把namespace內的某個指到的module換成的MagicMock object,所以要讓patch正確做事,我們必須
1. 確保patch的東西是被測試的file(connection.py)看得到的人
2. 確認在測試file(test_connection.py)中對應的module可以被import
我們以前列的connection.py為例子
```python=
# connection.py in ./app
import requests
def connection():
# try to call a website
# default it return 200
response = requests.get('https://www.google.com.tw/')
return response.status_code
```
這時候如果在這裡dir(),如同上個章節所言,我們會得到
```
[..., 'requests']
```
所以,如果在測試中要patch掉這裡的requests,以patch的定義來說,我們必須
**patch("app.connection.requests")**
最後,不管用得是patch還是patch.object,他們的souce code其實最後都一樣,所以如果用的是patch.object的注意事項也一樣
```python=
return _patch(
getter, attribute, new, spec, create,
spec_set, autospec, new_callable, kwargs, unsafe=unsafe
)
```
> 有興趣的可以去這裡 https://github.com/python/cpython/blob/main/Lib/unittest/mock.py#L1317
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch
## 後記
本篇是遠遠不到講完,甚至可能連講清楚都欠奉的一篇文章,所以理所當然的有下集(~~其實是寫不完~~)
下一篇文繼續深入講解這個主題
令人混淆的mock.patch,他還是高人氣的秘密在哪裡呢?
主要會講講where to patch跟一些案例