mardi 16 juin 2020

pytest - patching a global variable before it's being created

I have a global variable used as a singleton for hardware access:

in a.py:

class _A():
    def __init__():
        # init hardware here
        ...
    def __del__():
        # close hardware connection

a = _A()

Obviously, I don't want my hardware initialized during testing, so I want to mock a, or _A before _A.init() is ever called.

I've tried monkeypatching it using a fixture:

@pytest.fixture
    def init_A(monkeypatch):
    monkeypatch.setattr('a._A.__init__', Mock())

def test_a(init_A):
    import a
    #patch a and use it here

Unfortunately, _A.__init__() is already called before the monkeypatch - I suspect that it's because monkeypatch has to import a in order to change it, but once a is imported, the init has already been called.

unittest.mock.patch also behaves the same, supposedly, for the same reason.

Is there a way to get around this?

I thought of using a lazily evaluated singleton:

from functools import wraps


def singleton(cls):
    @wraps(cls)
    def wrapper_singleton(*args, **kwargs):
        if not wrapper_singleton.instance:
            wrapper_singleton.instance = cls(*args, **kwargs)
        return wrapper_singleton.instance
    wrapper_singleton.instance = None
    return wrapper_singleton

This works, but for some reason I can't set debug breakpoints once my tests use this singleton... But I guess I'll open a new question regarding this issue, if indeed the global variable approach is as impossible as it seems.

Aucun commentaire:

Enregistrer un commentaire