我正在使用redis以下方式:
from redis import Redis
redis_client = Redis()
def get_datetime_from_redis(key):
start_time = redis_client.get(key)
start_time = datetime.strptime(datetime_as_string, "%Y-%m-%d %H:%M:%S.%f")
duration = (datetime.now() - start_time).total_seconds()
return duration
我想通過以下方式測驗該功能:
import pytest
from core.utils import get_datetime_from_redis
from unittest.mock import Mock
from datetime import datetime
def test_get_datetime_from_redis(monkeypatch):
mock_redis = Mock()
mock_redis.get.return_value = datetime(2022, 1, 26)
monkeypatch.setattr('core.utils.Redis', mock_redis)
get_datetime_from_redis('foo')
mock_redis.get.assert_called_once()
但問題是,在monkeypatch.setattr('core.utils.Redis', mock_redis)運行時,redis_client已經實體化了,所以我不是在嘲笑正確的版本。
我該如何應對這些型別的測驗?
uj5u.com熱心網友回復:
它是一個全域變數這一事實不應該成為問題:monckeypatch 可以應用于每個范圍甚至現有實體。
這里的問題是您使用 monckeypatch 夾具的方式。
由于該函式正在使用模塊中的redis_clent變數,因此夾具應該模擬它,而不是 Redis 類本身。core.utilsmonckeypatch
所以 :
import pytest
from core.utils import redis_client
from core.utils import get_datetime_from_redis
from datetime import datetime
def test_get_datetime_from_redis(monkeypatch):
redis_get_called = []
# define mock function
def mock_redis_get(self, k, default=None) :
get_called.append(1) # Add to call count
return datetime(2022, 1, 26)
# patch redis_client variable
monkeypatch.setattr(redis_client, 'get', mock_redis_get)
# act
get_datetime_from_redis('foo')
# assert
assert len(redis_get_called) == 1
現在只需注意Redisget方法的簽名:
你的 monckeypatch 應該有相同的簽名......這就是為什么這里的模擬函式還有一個self, k(而不是key)和一個default引數(我認為最后一個可以忽略,因為它是一個可選引數)
uj5u.com熱心網友回復:
不確定它是否能完全解決問題,但您應該設計您的測驗以fixture負責管理模擬 redis ( mock_redis) 的創建。通過將此代碼封裝在一個夾具中,您將能夠在fixture創建時進行管理(每個會話、每個模塊、每個函式一次)并在一個位置收集所有這些代碼。
這是一個很好的例子,說明如何做到這一點。
第二點是您redis_client在代碼中實體化客戶端的方式。由于它不是在方法或類中完成的,redis_client因此在匯入模塊后立即創建。您還應該考慮通過將實體化放在可以在需要時呼叫的方法或類中來延遲實體化。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/422898.html
標籤:
