Python возвращает объект MagicMock вместо return_value

86

У меня есть файл python, a.pyкоторый содержит два класса Aи B.

class A(object):
    def method_a(self):
        return "Class A method a"

class B(object):
    def method_b(self):
        a = A()
        print a.method_a()

Я хотел бы UnitTest method_bв классе Bпо насмешливый A. Вот содержимое файла testa.pyдля этой цели:

import unittest
import mock
import a


class TestB(unittest.TestCase):

    @mock.patch('a.A')
    def test_method_b(self, mock_a):
        mock_a.method_a.return_value = 'Mocked A'
        b = a.B()
        b.method_b()


if __name__ == '__main__':
    unittest.main()

Я ожидаю получить Mocked Aрезультат. Но вот что я получаю:

<MagicMock name='A().method_a()' id='4326621392'>

Где я делаю не так?

Мехди Джафарния Джахроми
источник
1
При тестировании A()возвращает return_valuefrom mock_A(обычный MagicMock, поскольку вы ничего не указали), который не является экземпляром класса A. Вам нужно установить это return_valueкак то, что имеет определенный method_a.
jonrsharpe 05
3
mock_a.method_a.return_value = 'Mocked A' => mock_a (). method_a.return_value = 'Mocked A' должен быть лучше :)
Али СКАЗАЛ ОМАР
@AliSAIDOMAR совершенно правильно, это возвращаемое значение от вызова, mock_aкоторое должно иметь метод, а не он mock_aсам.
jonrsharpe 05
1
@jonrsharpe. Спасибо за ваше объяснение. Я просто попробовал. Оба так mock_a().method_a.return_value = 'Mocked A'и mock_a.return_value.method_a.return_value = 'Mocked A'работали. Большое спасибо за ваши комментарии. Не могли бы вы сформулировать это как ответ?
Мехди Джафарния Джахроми 05
@MehdiJafarniaJahromi большое спасибо!
Ниакрос

Ответы:

96

Когда @mock.patch('a.A')вы заменяете класс Aв тестируемом коде на mock_a.

В B.method_bвас тогда набор a = A(), который в настоящее время a = mock_a()- то есть aэто return_valueиз mock_a. Поскольку вы не указали это значение, это обычное MagicMock; это тоже не настроено, поэтому вы получите ответ по умолчанию (еще один MagicMock) при вызове его методов.

Вместо этого, вы хотите настроить от иметь соответствующий метод, который вы можете сделать либо как:return_valuemock_a

mock_a().method_a.return_value = 'Mocked A' 
    # ^ note parentheses

или, возможно, более явно:

mock_a.return_value.method_a.return_value = 'Mocked A'

Ваш код сработал бы в этом случае a = A(присвоение класса, а не создание экземпляра), поскольку тогда a.method_a()сработал бы ваш фиктивный метод.

Джонршарп
источник
4
Потрясающие. Вы сделали мой день.
Vishal
Привет @jonrsharpe, я использую фреймворк pandas с df.columns, чтобы проверить мое условие if . В нем не используются круглые скобки (т. Е. Он не вызывается). Что мне делать, чтобы вернуть список в таком случае. Благодарность!
imsrgadich 08
@imsrgadich для этого нужен макет ? Просто создайте соответствующий фрейм данных, рассматривайте его как тестовое значение.
jonrsharpe
@jonrsharpe да, я мог бы это сделать, но я также выполняю df.drop в моем вызываемом методе, который мне нужно подтвердить, и над тем, что я не возвращаю фрейм данных обратно из вызываемого метода. Это создает проблему. Я нашел способ, mock_data.configure_mock(columns='my_column')который решает эту проблему. Спасибо за ответ. ( Ссылка : bradmontgomery.net/blog/how-world-do-you-mock-name-attribute )
imsrgadich 08
Это не работает, если вы имитируете две модели SQLAlchemy в одном тесте. Первый работает нормально, но второй вернет MagicMock независимо от того, что вы определяете.
Юха Унтинен