How to use fudge.patch with pytest

479 views Asked by At

I'm switching from nose to pytest and having problems using fudge to create mocks/fakes because @fudge.patch passes them into the test function but pytest interprets test function arguments as fixtures.

I'm wondering if pytest and fudge are fundamentally incompatible, or if there's a trick I'm missing. I prefer fudge to mock because it allows you to set up expectations more intuitively, all in one place before you test something, whereas mock splits things up by defining return values before the test and expected calls after.

With nose I could monkey-patch with a fudge.Fake like this:

from datetime import datetime
from fudge import patch

def today():
    return datetime.utcnow()

def something():
    return today()

test_time = datetime(2018, 1, 1, 12, 34, 56)

@patch('today')
def test_something(fake_today):
    fake_today.expects_call().returns(test_time)
    result = something()
    assert result == test_time

Note how fudge lets you set expected calls and fake returns in one place, which I find more intuitive than the way mock does it.

However, using pytest this raises an exception because pytest interprets arguments to test functions as fixtures, and doesn't know a fixture called fake_today:

test setup failed
file example.py, line 13
  @patch('today')
  def test_something(fake_today):
E       fixture 'fake_today' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

I could declare a fake_today as a fixture, but I don't think pytest checks expectations, and if it does then the fixture would always have the same expectations wherever it's used, which doesn't always make sense.

I could use the monkeypatch fixture in test functions to inject Fakes, but that's not as neat as using a decorator.

I could also define fixtures that return a Fake like this:

@pytest.fixture
def request(monkeypatch):
    """
    Fake Session.request method so tests can mock expected REST requests.
    """
    fake_request = fudge.Fake()
    monkeypatch.setattr('requests.sessions.Session.request', fake_request)
    yield fake_request
    fudge.verify()

But you have to do that for every Fake you want to inject, which seems clunky.

Not sure what's the best way.

1

There are 1 answers

0
quantoid On

According to this issue comment fudge is not intended to be compatible with pytest.