azzamsa
azzamsa

Reputation: 2125

How to fake Popen in test?

I've successfully Faked other module with my own Fake implementation or using monkeypatch. But in this case using both fake implementation or monkeypatch failed for subprocess.Popen:

class TestController:

    def test_get_all_windows(self, ctrl_fixture, monkeypatch):

        def fake_communicate(a):
            return "foo"

        monkeypatch.setattr(subprocess.Popen, 'communicate', fake_communicate)
        output = ctrl_fixture.get_all_windows()
        print(output)

class FakePopen(object):
    def __init__(self, args, stdout=None):
        super().__init__()      
        self.args = args
        self.stdout = stdout

    def communicate(self):
        return "foo"

class TestController:
    def test_get_all_windows(self, ctrl_fixture, monkeypatch, mocker):

        def fake_communicate(a):
            return "foo"
        subprocess.Popen = FakePopen
        subprocess.Popen.communicate = fake_communicate
        output = ctrl_fixture.get_all_windows()
        print(output)

my function is:

    def get_all_windows(self):
        all_windows = ""
        all_windows_proc = Popen(["wmctrl", "-l"], stdout=PIPE)
        all_windows_dirty, err = all_windows_proc.communicate()
        for line in all_windows_dirty.splitlines():
            windows_name = line.split(None, 3)[-1].decode()
            all_windows += "{}\n".format(windows_name)
        return all_windows

The test above using print instead of assert cause I still want to check the output.

Thanks in advance.

Update solution

According to munk comments. Great thanks to him.

both solution worked:

def test_get_all_windows_one(self, ctrl, monkeypatch):

    window_title = b"0x006000ab  0 machine-name foo_window_title"

    def fake_communicate(a):
        return window_title, "err"

    Lupr.controllers.controller.Popen = FakePopen
    Lupr.controllers.controller.Popen.communicate = fake_communicate

    output = ctrl.get_all_windows()
    assert output == "foo_window_title\n"

def test_get_all_windows_two(self, ctrl, monkeypatch):

    window_title = b"0x006000ab  0 machine-name foo_window_title"

    def fake_communicate(a):
        return window_title, "err"

    monkeypatch.setattr(Lupr.controllers.controller, "Popen", FakePopen)
    monkeypatch.setattr(
        Lupr.controllers.controller.Popen, "communicate", fake_communicate
    )
    output = ctrl.get_all_windows()
    assert output == "foo_window_title\n"

Upvotes: 2

Views: 954

Answers (1)

munk
munk

Reputation: 13023

You're patching subprocess.Popen, but in your function under test you're using Popen directly. You're changing the wrong symbol table.

If your function is in foo.py, you want to patch foo.Popen or change your function to use subprocess.Popen.

Upvotes: 2

Related Questions