Размер терминала Pytest Monkeypatch - PullRequest
1 голос
/ 18 февраля 2020

Я играю с прибором monkeypatch в pytest, пытаясь смоделировать текущий размер окна терминала.

import os
import pytest

def get_terminal_size():
    terminal_size = os.popen('stty size', 'r').read()
    return terminal_size

def test_get_terminal_size(monkeypatch):
    # The get_terminal_size() function will return a string 'height width\n'
    def mock_size():
        return '10 20\n'

    monkeypatch.setattr(os.popen('stty size', 'r'), 'read', mock_size)

    assert get_terminal_size() == '10 20\n'

Когда я запускаю pytest, я получаю ошибку подтверждения:

__________________________________________________________________ test_get_terminal_size __________________________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f5bf1ec0cf8>

    def test_get_terminal_size(monkeypatch):
        # The get_terminal_size() function will return a string 'height width\n'
        def mock_size():
            return '10 20\n'

        monkeypatch.setattr(os.popen('stty size', 'r'), 'read', mock_size)

>       assert get_terminal_size() == '10 20\n'
E       AssertionError: assert '' == '10 20\n'
E         + 10 20

test_monkeypatch.py:15: AssertionError

Похоже, он не устанавливает mock_size. Я пытался следовать шаблону из документации Pytest

Есть ли какие-либо предложения о том, как заставить это работать?

Заранее спасибо!

Обновление: Как указал Кент Шикама в ответе ниже, для способа, которым я пытался захватить вывод, мне нужно было использовать флаг -s, чтобы отключить захват пестицидов.

Но с дальнейшими исследованиями об использовании popen, в частности, о переходе от использования os.popen к подпроцессу. Откройте, см. здесь и некоторую помощь из этого SO post на "Как подделать Попен" Я нашел решение.

вот новая настройка:

# \mokeypatch_popen.py
from subprocess import Popen

def get_terminal_size():
    terminal_size = Popen('stty size', shell=True)
    return terminal_size

Функция тестирования:

# \test_monkeypatch.py
import pytest
import monkeypatch_popen

def test_get_terminal_size(monkeypatch):
    # The get_terminal_size() function will return a string 'height width\n'
    def mock_terminal_size(cmd, **kwargs):
        return '10 20\n'

    monkeypatch.setattr(m_patch, 'Popen' , mock_terminal_size)

    assert m_patch.get_terminal_size() == '10 20\n'

Поначалу для меня неочевидным было то, что функция mock_terminal_size будет обрабатывать параметры метода Popen, над которым она работает, поэтому она должна принимать параметры, используемые Popen в исходной функции. Я мог бы специально добавить параметр оболочки в mock_terminal_size, но, поскольку Popen принимает длинный список kwargs, я был немного более неоднозначным.

Это теперь проходит, когда я запускаю pytest, и флаг -s не нужен, так как я я больше не пытаюсь захватить вывод, но высмеиваю выполнение метода Popen.

1 Ответ

1 голос
/ 18 февраля 2020

Во-первых, вам нужно запустить pytest с флагом -s, иначе stty будет захвачен. И тогда вы должны получить ошибку подтверждения, которую вы, вероятно, ожидали, следующим образом:

>       assert get_terminal_size() == '10 20\n'
E       AssertionError: assert '24 80\n' == '10 20\n'
E         - 24 80
E         + 10 20

Похоже, вы хотите смоделировать метод чтения в потоке так, чтобы он всегда выполнял «10 20». Обычно вы делаете что-то вроде

from io import TextIOWrapper
monkeypatch.setattr(TextIOWrapper, 'read', mock_size)

, но, к сожалению, вы не можете высмеивать встроенный объект. Вы можете попробовать что-то вроде запретный плод , чтобы преодолеть это, но такое чувство, что вы можете изменить свой подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...