kvas-it / pytest-console-scripts

Pytest plugin for testing console scripts
MIT License
78 stars 14 forks source link

Can I mock a function in the called script? #40

Closed carmocca closed 4 years ago

carmocca commented 4 years ago

Im having trouble mocking a function in the script im calling. Is it possible?

file: foo.py

def func(x):
    raise Exception

if __name__ == "__main__":
    func('works!')

file: test.py

import foo

def test(script_runner, monkeypatch):
    monkeypatch.setattr(foo, "func", lambda x: print(x))

    # this does print
    foo.func("mocked function!")

    ret = script_runner.run("foo.py")

    # however, this does not work, an exception is raised
    assert ret.success

Thank you.

kvas-it commented 4 years ago

It should work in in-process mode but not in subprocess mode (because in that case you're starting a separate process so the mocking won't apply). To ensure your test runs in in-process mode you can add this decorator to it:

@pytest.mark.script_launch_mode('inprocess')

Let me know if this doesn't work. This would be a bug that I'd want to fix.

carmocca commented 4 years ago

Isn't inprocess the default launch mode? In any case, it still does not work when I set it explicitly

kvas-it commented 4 years ago

Yeah, you're right, mocking in the script itself doesn't work even in in-process mode. The reason for that is that the script is not imported via the usual module machinery but is compiled and executed directly instead. There are two problems with importing it as a module:

  1. it might not be accessible (not in the path and/or not a .py file),
  2. if we import it as a module, __name__ will not be "__main__", so if __name__ == '__main__': block that many scripts have would not execute, which would mess things up.

It's possible to work around (1), at least we could use the module if it is importable, but I don't see a way to work around (2) without lots of hacks that I'd rather not go into.

If it helps, you can import other modules into the script and mock objects in those modules. Any module that you can import into the script and into the test you can mock (and I added a test for this now), just not the script itself.

carmocca commented 4 years ago

I figured it was a hard limitation. Thanks for the quick response!

Also, great job on the plugin :+1:

kvas-it commented 4 years ago

Also, great job on the plugin 👍

Thank you!