Home > Software engineering >  Pytest: How to test a function that contains a global variable?
Pytest: How to test a function that contains a global variable?

Time:01-27

I am using redis in the following way:

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

I'd like to test the function in the following way:

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()
    

But the issue is that by the time that monkeypatch.setattr('core.utils.Redis', mock_redis) is run, redis_client is already instantiated, so I'm not mocking the correct version.

How do I address these kinds of tests?

CodePudding user response:

Not sure it will solve entirely the problem but you should design your tests to have a fixture in charge of managing the creation of the mocked redis (mock_redis). By encapsulating this code in a fixture you will be able to manage when the fixture is created (once per session, per module, per function) and to gather all this code at a single location. Here is a good example on how to do that.

Second point is on the way you instantiate redis_client client in your code. Since it's not done in a method or in a class, redis_client is created as soon as the module is imported. You should also consider deferring the instantiation by putting it in a method or class you can call when needed.

CodePudding user response:

Since the function is consuming the global variable of the module, your monckeypatch should mock it.

So :

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 = []
    def mock_redis_get(key) :
        get_called.append(1) # Add to call count
        return datetime(2022, 1, 26)
    monkeypatch.setattr(redis_client, 'get', mock_redis_get)
    get_datetime_from_redis('foo')
    assert len(redis_get_called) == 1
  •  Tags:  
  • Related