mockito-python icon indicating copy to clipboard operation
mockito-python copied to clipboard

Mocking sys.argv and sys.stdout like in patch

Open relte opened this issue 6 years ago • 4 comments

Is it possible to use Mockito to replace sys.argv or sys.stdout?

I could do it with unittest.mock.patch but I'd rather use a single mocking tool:

def it_outputs_answers_based_on_an_argument(when):
    with patch('sys.argv', ['cli.py', 'all']):
        when('app.cli.ApiClient').search_answers('all').thenReturn([
            {
                'id': 1,
                'question': 'A?',
                'content': 'B'
            }
        ])

        with patch('sys.stdout', StringIO()) as stdout:
            main()
            output = stdout.getvalue().strip()
            expect(output).to(equal('A?\n--\nB'))

relte avatar Oct 12 '18 20:10 relte

Afaik this is not possible. Historically mockito is completely focused on stubbing/patching callables. I want this too and actually have it on my to-do list but you can try a PR if you want to.

kaste avatar Oct 12 '18 21:10 kaste

Two cents here:

  • Since mocking and esp. monkey patching in python in general is very easy, if I look at your example code, it seems that testing and testability is not any guard and guide when designing the API anymore. E.g. if you had defined def main(argv=sys.argv, stdout=sys.stdout) (t.i with boring, standard dependency injection) there wouldn't be any need for monkey-patching.

  • What you want patch to do is super simple.

@contextmanager
def patch(obj, attr, replacement):
	original = getattr(obj, attr, None)
	setattr(obj, attr, replacement)
	try:
		yield replacement
	finally:
		if original:
			setattr(obj, attr, original)
		else:
			delattr(obj, attr)

It becomes more complicated within the mockito framework of course. (Do you know pytests's monkeypatch fixture?)

kaste avatar Oct 14 '18 21:10 kaste

True, with dependency injection it'd be another story but AFAIK it's not the "pythonic way" of doing things. I'm new to Python, especially the testing part and I find Mockito the friendliest for mocking.

I read about monkeypatch but it doesn't seem much different from mocker.patch. Or am I missing something?

By the way as to my test, I use Click now so it got simpler because of its helper.

relte avatar Oct 15 '18 10:10 relte

I read about monkeypatch but it doesn't seem much different from mocker.patch. Or am I missing something?

monkeypatch is far less complex. It's just a couple of lines, similar to what I posted above. mock.patch is, just like mockito, way more code.

(I hate if people say something is not 'pythonic'. If it's a small tool, go and monkeypatch globals, if it grows inject the dependencies to stay flexible, extensible.)

kaste avatar Oct 19 '18 19:10 kaste