fixture 的英文是夾具,也許是為了和 python 的裝飾器有個呼應所以才叫這個名字吧? 這邊整理一些比較常見的 fixture 用法,可以根據大家的測試情境去做搭配
提高重複利用率
舉個例子,我們想測試下面這段 redis 的連線可不可以正常的讀寫資料,所以我分別寫了三個測試
python
from redis import Redis
def create_redis(db: int = 0):
return Redis(host='127.0.0.1',
port=6379,
decode_responses=True,
retry_on_timeout=True,
db=db)
python
from db import create_redis
def test_redis_set():
r = create_redis()
r.set(name='user:Nick', value=1)
def test_redis_get():
r = create_redis()
assert int(r.get(name='user:Nick')) == 1
def test_redis_keys():
r = create_redis()
print(r.keys())
可以看到操作 redis 的 set
, get
, keys
都需要先建立 redis 連線,因此我們可以透過 fixture
減少程式碼重複呼叫連線
python
import pytest
from db import create_redis
@pytest.fixture
def redis_conn():
return create_redis()
def test_redis_set(redis_conn):
redis_conn.set(name='user:Nick', value=1)
def test_redis_get(redis_conn):
assert int(redis_conn.get(name='user:Nick')) == 1
def test_redis_keys(redis_conn):
print(redis_conn.keys())
fixture + fixture
fixture 可以無限套娃
例如這邊的例子是我想測試 redis 的 pipeline,我依然可以利用剛剛建好的 fixture redis_conn
來幫忙建立新的 fixture
python
@pytest.fixture
def pipe(redis_conn):
pipe = redis_conn.pipeline()
return pipe
def test_pipeline_set(pipe):
pipe.set(name='user:Nick', value=1)
pipe.set(name='user:foo', value=2)
pipe.set(name='user:bar', value=3)
pipe.set(name='user:baz', value=4)
pipe.execute()
pipe.close()
fixture yield
上面 pipeline 的例子能看到我最後調用 close
去關閉 pipeline 連線,不過我們能透過 pipeline 的上下文管理更好的關閉連線
這邊就提供一個在 fixture 中 yield pipeline 出來的例子
python
@pytest.fixture
def pipe(redis_conn):
with redis_conn.pipeline() as pipe:
yield pipe
pipe.execute()
def test_pipeline_set(pipe):
pipe.set(name='user:Nick', value=1)
pipe.set(name='user:foo', value=2)
pipe.set(name='user:bar', value=3)
pipe.set(name='user:baz', value=4)
fixture + parametrize
在上一篇文章中,我們透過 parametrize 來設置多個測資
而 fixture 也可以做到同樣的事,例如我們測試中輪流切換 redis 的三個庫
python
@pytest.fixture(params=[0, 1, 2])
def redis_conn(request):
return create_redis(db=request.param)
def test_redis_set(redis_conn):
redis_conn.set(name='user:Nick', value=1)
而 pytest.mark.parametrize
的作法則是
python
@pytest.fixture
def redis_conn(request):
return create_redis(request.param)
@pytest.mark.parametrize('redis_conn', [1, 2, 3], indirect=True)
def test_redis_set_with_difference_db(redis_conn):
redis_conn.set(name='user:Nick', value=1)
小結
今天只講到 fixture 用法的一小部分,不過都是我認為最實用的部分
當然後續還會再補上其他 fixture 的介紹,預期下一篇應該會整理整理 scope
的部分