Модуль Python pytest-mock, как проверить аргументы вызова метода, когда один класс вызывает другой экземпляр класса?

Я начал изучать модульное тестирование с помощью pytest пару дней назад и заинтересовался плагином pytest-mock (https://github.com/pytest-dev/pytest-mock).

Мне удалось написать довольно много модульных тестов для тестирования своего кода, но теперь я хотел бы проверить, как части моего кода взаимодействуют с другими объектами. Допустим, у меня есть класс B, который является классом, который меня интересует для тестирования, у которого есть метод, который будет вызывать метод в классе A, и я хотел бы утверждать, что вызов метода был сделан с ожидаемыми аргументами, когда класс B позвоните в класс A.

Я собрал несколько примеров взлома (см. Ссылку ниже), который выполнит эту работу, но, как вы можете видеть, это, вероятно, неправильный способ делать что-то. Итак, мой вопрос: как это правильно обрабатывать с помощью модулей Python mock или pytest-mock? Также приветствуются ответы, не основанные на плагине pytest-mock.

В приведенном ниже коде это утверждение, которое меня не устраивает, поскольку я бы предпочел использовать существующий метод pytest-mock "assert_called_once_with (...)", но я просто не могу заставить его работать. Вся информация доступна в mock-объекте, но я не понимаю, как правильно использовать pytest-mock API в этом случае.

def test_how_class_b_interact_with_class_a(mocker):
    class A(object):
        def further_process_nbr(self, nbr):
            pass # don't care for the sake of this example

    class B(object):
        def __init__(self):
            self.a = A()

        def process_nbr(self, nbr):
            nbr += 2 # do something fancy with number and then have it further processed by object a
            return self.a.further_process_nbr(nbr)

    nbr = 4
    expected = 6

    # Prepare
    mock_a = mocker.patch.object(A, 'further_process_nbr', autospec=True)

    # Exercise
    B().process_nbr(nbr)

    # Assert
    assert mock_a.call_args_list[0].args[1] == expected # This is working, but not exactly a nice way
    # mock_a.assert_called_once_with(expected) something like this is basically what I would like to do

person sxpy    schedule 20.01.2020    source источник


Ответы (1)


На самом деле результат, который вы видите, правильный, в:

assert (<a.A object at 0x000001628C6878B0>, 2) == (2,)

В первом элементе кортежа вы видите параметр self, потому что вы имитировали метод в классе, поэтому он также получает self.

Чтобы проверить это с помощью assert_called_once_with, вы можете использовать mocker.ANY, который примет все что угодно:

mock_a.assert_called_once_with(mocker.ANY, nbr)
person Bruno Oliveira    schedule 20.01.2020