Питон издеваться над разными экземплярами - PullRequest
0 голосов
/ 05 июня 2018

Я хотел бы знать разницу между pg.connect и pg.connect() утверждениями.

pg является фиктивным объектом psycopg2, и когда я отображаю dir, он показывает метод connect в качестве метода.

class TestMock(unittest.TestCase):
    def setUp(self):
        pass

    def test_mock_calls(self):
        import pprint
        pg = mock.MagicMock(psycopg2)
        print 'pg() object ', pg()
        print 'dir of pg = ', pprint.pprint(dir(pg))

        print 'dir of pg = ', pg.connect
        print 'dir of pg.connect = ', pprint.pprint(dir(pg.connect))

        print 'dir of pg = ', pg.connect()
        print 'dir of pg.connect() = ', 
        pprint.pprint(dir(pg.connect()))

Обновления: - Один (pg.connect) обращается к атрибуту, а другой (pg.connect ()) вызывает функцию.

Теперь, как мне установить return_valueметода execute?

Например: - мне нужно смоделировать ответ моего метода execute.

, поэтому это должен быть pg.connect (). cursor (). execute.side_effect= someexception ()

1 Ответ

0 голосов
/ 05 июня 2018

Python довольно буквально настроен.Выражение pg.connect() переводится в:

  1. Поиск имени pg
  2. Поиск атрибута connect для этого.
  3. Вызовите его с пустымАргументы.

Таким образом, выражение pg.connect получит метод, но не вызовет его.И, на самом деле, вы можете использовать этот метод в качестве обычного значения и передавать его, так что my_connect = pg.connect полностью допустим, и вы можете позже вызвать my_connect().

Мы можем увидеть, что происходит сdis module:

import dis
dis.dis(lambda: pg.connect())

 1           0 LOAD_GLOBAL              0 (pg)
             2 LOAD_ATTR                1 (connect)
             4 CALL_FUNCTION            0
             6 RETURN_VALUE

Поскольку Mock хочет притвориться разными объектами, он переопределяет стандартные методы __getattribute__ и __call__ и __eq__ dunder.В то время как объекты имеют нормальный способ предоставления атрибутов, __getattribute__ позволяет классу делать все, что он хочет, если атрибут запрашивается.

Когда вы называете его как Mock(spec=psycopg2), он будет делать две основные вещи иначе, чемMock():

  1. Он корректирует свое поле __class__, чтобы заявить, что оно psycopg2.
  2. Проверьте psycopg2 на предмет допустимых свойств и увеличьте AttributeError, если вы пытаетесь получитьполе, которого нет.

Но, кроме того, оно все еще ведет себя как обычный макет.Если вы вызываете yourMock.foo, он не знает, является ли это свойство или метод.Он просто возвращает новый экземпляр Mock, и поскольку этот экземпляр может вызываться, вы можете вызывать его как функцию.

Обновление: если вы задаете спецификацию на Mock, это ограничивает доступные атрибуты.Чтобы добавить атрибут, не предоставленный спецификацией, вам просто нужно установить его во время инициализации:

cursor_mock = Mock(side_effect=psycopg2.DatabaseError)
Mock(spec=psycopg2.connect, cursor=cursor_mock)

Вы также хотели это поведение: pg.connect().cursor().execute.side_effect = someexception().Как правило, вы можете изменить return_value:

cursor_mock = Mock()
cursor_mock.return_value.execute.side_effect = SomeException
# Same as:
cursor_mock = Mock(return_value=Mock(execute=Mock(side_effect=SomeException)))

Вы также можете сделать cursor_mock().execute.side_effect = SomeException, но это загрязняет cursor_mock.mock_calls.

Небольшое замечание: я использую Mock для краткости, и MagicMock - то же самое, просто добавив несколько более сложных методов.

...