Я пишу тесты для такой функции:
def foo():
print 'hello world!'
Поэтому, когда я хочу протестировать эту функцию, код будет примерно таким:
import sys
from foomodule import foo
def test_foo():
foo()
output = sys.stdout.getline().strip() # because stdout is an StringIO instance
assert output == 'hello world!'
Но если я провожу тесты с параметром -s, тест выйдет из строя. Как я могу поймать вывод с помощью unittest или носового модуля?
python
unit-testing
nosetests
python-nose
Педро Валенсия
источник
источник
with mock.patch('sys.stdout', new_callable=StringIO.StringIO):
pypi.python.org/pypi/mockОтветы:
Я использую этот диспетчер контекста для захвата вывода. В конечном итоге он использует ту же технику, что и некоторые другие ответы, путем временной замены
sys.stdout
. Я предпочитаю диспетчер контекста, потому что он объединяет всю бухгалтерию в одну функцию, поэтому мне не нужно переписывать какой-либо окончательный код, и мне не нужно писать функции настройки и удаления только для этого.Используйте это так:
Кроме того, поскольку исходное состояние вывода восстанавливается при выходе из
with
блока, мы можем настроить второй блок захвата в той же функции, что и первый, что невозможно с использованием функций настройки и разрыва, и становится многословным при написании try-finally блоки вручную. Эта возможность пригодилась, когда целью теста было сравнение результатов двух функций относительно друг друга, а не с некоторым заранее вычисленным значением.источник
TypeError: unicode argument expected, got 'str'
(тип, переданный для печати (str / unicode), не имеет значения).from io import BytesIO as StringIO
а в Python 3 простоfrom io import StringIO
. Думаю, в моих тестах проблема решилась.strip()
наunicode
вернулся изStringIO.getvalue()
?sys
. С помощью оператора импорта вы создаете локальную переменную с именем,stderr
которая получила копию значения вsys.stderr
. Изменения одного не отражаются на другом.Если вы действительно хотите это сделать, вы можете переназначить sys.stdout на время теста.
Однако, если бы я писал этот код, я бы предпочел передать функции необязательный
out
параметрfoo
.Тогда тест намного проще:
источник
StringIO
класс теперь необходимо импортировать изio
модуля.from io import StringIO
работает в Python 2.6+.from io import StringIO
Python 2,TypeError: unicode argument expected, got 'str'
при печати вы получите .with redirect_stdout(out):
saved_stdout = sys.stdout
, у вас всегда есть магическая ссылка на этоsys.__stdout__
, например, вам нужно толькоsys.stdout = sys.__stdout__
в вашей очистке.Начиная с версии 2.7, переназначение больше не требуется
sys.stdout
, это обеспечиваетсяbuffer
флагом . Более того, это поведение по умолчанию.Вот пример ошибки в небуферизованном контексте:
Вы можете установить буфер через
unit2
флаг командной строки-b
,--buffer
или вunittest.main
опции. Обратное достигается с помощьюnosetest
флага--nocapture
.источник
--nocapture
; в частности, если этот флаг установлен, буферизованный режим будет отключен. Таким образом, у вас есть возможность либо увидеть вывод на терминале, либо проверить, что вывод соответствует ожиданиям.Многие из этих ответов не
from StringIO import StringIO
помогли мне, потому что вы не можете этого сделать в Python 3. Вот минимальный рабочий фрагмент, основанный на комментарии @ naxa и Поваренной книге Python.источник
В python 3.5 вы можете использовать
contextlib.redirect_stdout()
иStringIO()
. Вот модификация вашего кодаисточник
redirect_stdout()
иredirect_stderr()
вернуть их входной аргумент. Итак,with contextlib.redirect_stdout(StringIO()) as temp_stdout:
все в одной строке. Проверено с 3.7.1.Я только изучаю Python и обнаружил, что борюсь с проблемой, аналогичной описанной выше, с модульными тестами для методов с выводом. Мой прохождение модульного теста для модуля foo выше в конечном итоге выглядел так:
источник
sys.stdout.getvalue().strip()
а не обмануть, сравнивая с\n
:)from io import StringIO
Написание тестов часто показывает нам лучший способ написать наш код. Подобно ответу Шейна, я хотел бы предложить еще один способ взглянуть на это. Вы действительно хотите утверждать, что ваша программа выдала определенную строку или просто создала определенную строку для вывода? Это становится легче проверить, поскольку мы, вероятно, можем предположить, что
print
оператор Python выполняет свою работу правильно.Тогда ваш тест очень прост:
Конечно, если вам действительно нужно проверить фактический результат работы вашей программы, не обращайте внимания. :)
источник
foo()
ничего не делает, кроме вызова оператора печати, это, вероятно, не проблема.Основываясь на ответе Роба Кеннеди, я написал версию диспетчера контекста на основе классов для буферизации вывода.
Использование похоже:
Вот реализация:
источник
Или рассмотрите возможность использования
pytest
, он имеет встроенную поддержку для утверждения stdout и stderr. См. Документыисточник
Оба n611x007 и Ноумен уже предложили использовать
unittest.mock
, но этот ответ адаптирует Акаменус - х , чтобы показать , как можно легко обернутьunittest.TestCase
методы , чтобы взаимодействовать с издевалсяstdout
.источник
Основываясь на всех замечательных ответах в этой теме, я решил эту проблему следующим образом. Я хотел, чтобы он был как можно более стоковым. Я расширил механизм модульного тестирования, используя
setUp()
для захватаsys.stdout
иsys.stderr
, добавил новые API-интерфейсы assert, чтобы проверять захваченные значения на соответствие ожидаемому значению, а затем восстанавливатьsys.stdout
иsys.stderr
послеtearDown(). I did this to keep a similar unit test API as the built-in
unittestAPI while still being able to unit test values printed to
sys.stdoutor
sys.stderr`.Когда запускается модульный тест, на выходе получается:
источник