Как распечатать на консоли в pytest?


175

Я пытаюсь использовать TDD (разработка через тестирование) с pytest. pytestне будет printк консоли, когда я использую print.

Я использую, pytest my_tests.pyчтобы запустить его.

documentation, Кажется, говорят , что он должен работать по умолчанию: http://pytest.org/latest/capture.html

Но:

import myapplication as tum

class TestBlogger:

    @classmethod
    def setup_class(self):
        self.user = "alice"
        self.b = tum.Blogger(self.user)
        print "This should be printed, but it won't be!"

    def test_inherit(self):
        assert issubclass(tum.Blogger, tum.Site)
        links = self.b.get_links(posts)
        print len(links)   # This won't print either.

Ничего не выводится на мою стандартную консоль вывода (только обычный прогресс и сколько тестов пройдено / не выполнено).

И скрипт, который я тестирую, содержит print:

class Blogger(Site):
    get_links(self, posts):
        print len(posts)   # It won't get printed in the test.

В unittestмодуле все печатается по умолчанию, а это именно то, что мне нужно. Тем не менее, я хочу использовать pytestпо другим причинам.

Кто-нибудь знает, как заставить показывать операторы печати?


1
Может быть, стандартный вывод перезаписывается. Что произойдет, если вы используете sys.stdout.write("Test")? Как насчет sys.__stdout__.write("Test")? Последний всегда должен записывать в системный стандартный вывод, который должен быть консолью. Если две команды делают разные вещи, то stdout изменяется; если они делают то же самое, то проблема в другом.
TheSoundDefense

Ответы:


205

По умолчанию py.testфиксирует результат стандартного вывода, чтобы он мог контролировать способ его вывода. Если бы он этого не делал, он бы выбросил много текста без контекста того, какой тест печатал этот текст.

Однако, если тест не пройден, он будет включать в итоговый отчет раздел, в котором будет показано, что было напечатано в стандарте в этом конкретном тесте.

Например,

def test_good():
    for i in range(1000):
        print(i)

def test_bad():
    print('this should fail!')
    assert False

Результаты в следующем выводе:

>>> py.test tmp.py
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py .F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
------------------------------- Captured stdout --------------------------------
this should fail!
====================== 1 failed, 1 passed in 0.04 seconds ======================

Обратите внимание на Captured stdoutраздел.

Если вы хотите видеть printоператоры по мере их выполнения, вы можете передать -sфлаг py.test. Тем не менее, обратите внимание, что иногда это может быть трудно разобрать.

>>> py.test tmp.py -s
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py 0
1
2
3
... and so on ...
997
998
999
.this should fail!
F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
====================== 1 failed, 1 passed in 0.02 seconds ======================

2
В высшей степени практично. Прекрасная работа!
CMC

1
хм ... все еще не регистрирует мои печатные заявления
Тим Болэнд

68

При использовании -sопции будет напечатан вывод всех функций, которых может быть слишком много.

Если вам нужен конкретный вывод, упомянутая страница документации предлагает несколько советов:

  1. Вставьте assert False, "dumb assert to make PyTest print my stuff"в конце своей функции, и вы увидите ваш вывод из-за неудачного теста.

  2. У вас есть специальный объект, переданный вам PyTest, и вы можете записать вывод в файл для последующей проверки, например:

    def test_good1(capsys):
        for i in range(5):
            print i
        out, err = capsys.readouterr()
        open("err.txt", "w").write(err)
        open("out.txt", "w").write(out)
    

    Вы можете открыть файлы outи errна отдельной вкладке и позволить редактору автоматически обновить его для вас, или выполнить простую py.test; cat out.txtкоманду оболочки для запуска теста.

Это довольно хакерский способ делать вещи, но, возможно, это то, что вам нужно: в конце концов, TDD означает, что вы портите вещи и оставляете их чистыми и тихими, когда они готовы :-).


я пробовал версию 1. с pytest 3.8.1, к сожалению, он только печатает функциональный блок теста, но не выводит операторы print :( Есть еще уловки для этого?
UV

@UV - вместо использования print()функции вы должны поместить переменную или сообщение, которое вы хотите напечатать после запятой в операторе assert. Например assert False, what_are_you, «распечатает» значение what_are_youв отчете Pytest.
Март Ван де Вен

43

Короткий ответ

Используйте -sопцию:

pytest -s

Подробный ответ

Из документов :

Во время выполнения теста все выходные данные, отправленные на stdout и stderr, регистрируются . Если тест или метод настройки не пройден, его соответствующий захваченный вывод обычно отображается вместе с отслеживанием ошибок.

pytestимеет возможность , --capture=methodв котором methodнаходится за испытание метода захвата, и может быть одним из следующих: fd, sysили no. pytestтакже имеет опцию, -sкоторая является ярлыком для --capture=no, и это опция, которая позволит вам видеть ваши операторы печати в консоли.

pytest --capture=no     # show print statements in console
pytest -s               # equivalent to previous command

Настройка методов захвата или отключение захвата

Есть два способа pytestзахвата:

  1. захват уровня дескриптора файла (FD) (по умолчанию): все записи, поступающие в дескрипторы файлов операционной системы 1 и 2, будут перехвачены.

  2. Захват уровня sys : будут записываться только файлы Python: sys.stdout и sys.stderr. Захват записи в файловые дескрипторы не выполняется.

pytest -s            # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd  # also point filedescriptors 1 and 2 to temp file

17

Мне нужно было напечатать важное предупреждение о пропущенных тестах именно тогда, когда PyTestзаглушено буквально все .

Я не хотел проваливать тест, чтобы послать сигнал, поэтому я сделал хак следующим образом:

def test_2_YellAboutBrokenAndMutedTests():
    import atexit
    def report():
        print C_patch.tidy_text("""
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.""")
    if sys.stdout != sys.__stdout__:
        atexit.register(report)

atexitМодуль позволяет мне печатать материал после PyTest освободили выходные потоки. Вывод выглядит следующим образом:

============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /media/Storage/henaro/smyth/Alchemist2-git/sources/C_patch, inifile: 
collected 15 items 

test_C_patch.py .....ssss....s.

===================== 10 passed, 5 skipped in 0.15 seconds =====================
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.
~/.../sources/C_patch$

Сообщение печатается даже PyTestв беззвучном режиме и не печатается, если вы запускаете что-либо py.test -s, поэтому все уже хорошо протестировано.


1
Идеально подходит для вывода пользовательских тестовых показателей.
z0r


2

Первоначально я пришел сюда, чтобы найти способ PyTestпечати в консоли VSCode при запуске / отладке модульного теста оттуда. Это можно сделать с помощью следующей launch.jsonконфигурации. Учитывая .venvпапку виртуальной среды.

    "version": "0.2.0",
    "configurations": [
        {
            "name": "PyTest",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "module": "pytest",
            "args": [
                "-sv"
            ],
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.venv",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }
    ]
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.