В Mock Python встроена функция печати
Я пробовал
from mock import Mock
import __builtin__
__builtin__.print = Mock()
Но это вызывает синтаксическую ошибку. Я также попытался исправить его так
@patch('__builtin__.print')
def test_something_that_performs_lots_of_prints(self, mock_print):
# assert stuff
Есть ли способ сделать это?
Ответы
Ответ 1
print
- это ключевое слово в python 2.x, используя его как атрибут, повышает значение SyntaxError. Вы можете избежать этого, используя from __future__ import print_function
в начале файла.
Примечание. Вы не можете просто использовать setattr
, потому что функция печати, которую вы модифицировали, не вызывается, если оператор print
не отключен.
Изменить: вам также нужно from __future__ import print_function
в каждом файле, для которого вы хотите использовать измененную функцию print
, или она будет замаскирована оператором print
.
Ответ 2
Я знаю, что уже есть принятый ответ, но есть более простое решение для этой проблемы - издевательская печать в python 2.x. Ответ находится в учебнике макетной библиотеки: http://www.voidspace.org.uk/python/mock/patch.html, и это:
>>> from StringIO import StringIO
>>> def foo():
... print 'Something'
...
>>> @patch('sys.stdout', new_callable=StringIO)
... def test(mock_stdout):
... foo()
... assert mock_stdout.getvalue() == 'Something\n'
...
>>> test()
Конечно, вы также можете использовать следующее утверждение:
self.assertEqual("Something\n", mock_stdout.getvalue())
Я проверил это решение в своих unittests и работает как ожидалось. Надеюсь, это поможет кому-то. Ура!
Ответ 3
Это гораздо более простое решение Python 3 - проще использовать unittest.mock
непосредственно во встроенной функции print
, а не возиться с sys.stdout
:
import builtins
from unittest.mock import patch, call
@patch('builtins.print')
def test_print(mocked_print):
print('foo')
print()
assert mocked_print.mock_calls == [call('foo'), call()]
Ответ 4
Если вы хотите придерживаться инструкции print
от 2.x в отличие от функции print()
из 2.x, вы можете вместо этого высмеять ваш sys.stdout
.
Напишите фиктивный "файл", возможно, примерно таким образом:
class Writable(object):
"""Class which has the capability to replace stdout."""
newwrite = None
def __init__(self, oldstdout, newwrite=None):
self.oldstdout = oldstdout
if newwrite is not None:
self.newwrite = newwrite
def write(self, data):
self.newwrite(self.oldstdout, data)
@classmethod
def subclass(cls, writefunc):
newcls = type('', (cls,),
dict(write=lambda self, data: writefunc(self.oldstdout, data)
return newcls
Этот класс предполагает объединение с функцией записи, которая получает печатные данные. Предполагается, что эта функция записи принимает два аргумента: первый с "старым stdout", который будет использоваться для печати в конце, и еще один для данных.
Возьмем
def mywrite(sink, data):
sink.write(data.encode("hex"))
для этого.
Теперь вы можете сделать
import sys
sys.stdout = Writable(sys.stdout, mywrite)
или вы можете сделать
@Writable.subclass
def mywritable(sink, data)
sink.write(data.encode("hex"))
sys.stdout = mywritable(sys.stdout)
Вторая версия немного сложнее: она создает подкласс Writable
с помощью функции декоратора, которая превращает данную функцию в метод созданного вместо этого нового класса и помещает в имя, где данная функция происходит от.
После этого у вас есть новый класс, который может быть создан с помощью "старого stdout" в качестве аргумента и после этого может заменить sys.stdout
.
Ответ 5
Моя версия.
В тестируемой программе (например: pp.py
):
from __future__ import print_function
def my_func():
print('hello')
В тестовой программе:
def test_print(self):
from pp import my_func
from mock import call
with mock.patch('__builtin__.print') as mock_print:
my_func()
mock_print.assert_has_calls(
[
call('hello')
]
)
Ответ 6
import mock
import sys
mock_stdout = mock.Mock()
sys.stdout = mock_stdout
print 'Hello!'
sys.stdout = sys.__stdout__
print mock_stdout.mock_calls
[call.write('Hello!'), call.write('\n')]
Ответ 7
Сначала модуль называется __builtins__
, и его не нужно импортировать.
Теперь в Python 2 print
есть ключевое слово, поэтому вы не можете использовать его как имя атрибута напрямую. Вы можете использовать setattr
/getattr
, чтобы обойти его:
getattr(__builtins__, "print")
Другой вариант - использовать from __future__ import print_function
, который изменяет, как Python анализирует модуль на синтаксис Python 3.
Ответ 8
Как говорит lcq, print - это ключевое слово. Итак, подумайте о том, что это значило бы, если бы вы действительно добились исправления/издевки печати под Python 2.7.3. У вас будет такой код:
print "Hi."
превращается в:
<MagicMock id='49489360'> "Hi."
Объекты MagicMock не могут быть доступны таким образом, поэтому вы получите синтаксическую ошибку.
Итак... Да. Вы можете только фальсифицировать функцию печати Python3 или sys.stdout.
Ответ 9
Этот пример Python 3 основывается на ответе Python 2 от Krzysztof. Он использует unittest.mock
. Он использует метод повторного использования для утверждения.
import io
import unittest
import unittest.mock
from .solution import fizzbuzz
class TestFizzBuzz(unittest.TestCase):
@unittest.mock.patch('sys.stdout', new_callable=io.StringIO)
def assert_stdout(self, n, expected_output, mock_stdout):
fizzbuzz(n)
self.assertEqual(mock_stdout.getvalue(), expected_output)
def test_only_numbers(self):
self.assert_stdout(2, '1\n2\n')