# pytest fixture的分級(scope)
###### tags: `unit-test` `pytest`
閱讀本文前,我們會假設各位都知道 fixture是一個"測試單元都能拿去用的公共物件"
先上個例子
```python=
@pytest.fixture
def db():
# open db
yield
# close db
def test1(db):
logging.info("test1 use db")
def test2(db):
logging.info("test2 use db")
```
現在我們有一個fixture跟兩個測試,如果他們都需要跟db交互的話,會發生什麼事呢?
在上面這個範例中,fixture會被運行兩次。但如果在測試情境上,我們覺得db其實不用每次都重新打開一次要怎麼辦?
當我們在cmd中運行pytest的瞬間,這個fixture就會在每個測試開始的時候將db打開並yield住,保持db開啟,並在測試結束時關閉db,沒有問題,也不會出錯。
但今天如果這個打開db的行為是另外一個相當耗時或記憶體的行為時,又要怎麼辦呢?
於是在pytest fixture中,有scope這個參數,可以讓撰寫測試的各位決定fixture的觸發頻率,scope一共有五種。
## Function
預設的scope層級,會在每個test function結束後進行teardown並結束
## class
如果在撰寫測試單元時有用class把測試包起來,那麼在class內的測試可以用這個scope來確認在同個class內fixture只觸發一次
```python=
import pytest
@pytest.fixture(scope="class")
def my_fixture():
print("Setup")
yield
print("Teardown")
class TestClass:
def test_foo(self, my_fixture):
print("my_fixture setup once in this class")
def test_bar(self, my_fixture):
print("my_fixture setup once in this class")
```
## module
在同個file內的測試都會確保只觸發一次fixture
假設我們的資料夾結構長這樣
```
project/
├── tests/
│ ├── conftest.py
│ └── test_module1.py
│ └── test_module2.py
```
而我們的fixture長這樣
```python=
@pytest.fixture(scope="module")
def db():
# open db
yield
# close db
```
那麼test_module1.py與test_module2.py會各自觸發一次fixture
## package
在同個folder內的測試會觸發一次fixture
用跟上面一樣的資料夾結構
```
project/
├── tests/
│ ├── conftest.py
│ └── test_module1.py
│ └── test_module2.py
```
```python=
@pytest.fixture(scope="package")
def db():
# open db
yield
# close db
```
現在test_module1.py與test_module2.py只會觸發一次fixture了
## session
在整個測試流程中此fixture只會觸發一次
# 總結
其實還有很多小坑,包含fixture運作的順序,scope可以是動態等等,但本篇範例主要是讓各位理解,其實pytest可以用scope來讓撰寫測試的各位決定fixture該在什麼時候觸發。
有了以上這些分級的概念,相信各位在撰寫自己的測試時,就能根據不同fixture function的用途分配scope,最終達到節省測試總時長與消耗資源的目的。
如果有更多問題也歡迎詢問,或查閱官方文件如下:
https://docs.pytest.org/en/stable/how-to/fixtures.html#how-to-fixtures