Подтвердить что ты не робот

В 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

Есть ли способ сделать это?

4b9b3361

Ответ 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')