Насмешка над функцией, которая передается в качестве параметра во время инициализации переменной класса - PullRequest
0 голосов
/ 21 января 2019

scuevals_api / ресурсы / students.py

def year_in_range(year):
    return datetime.now().year <= year <= datetime.now().year + 10


class StudentsResource(Resource):
    args = {
        'graduation_year': fields.Int(required=True, validate=year_in_range),
    }

    ...

Я пытаюсь издеваться year_in_range (чтобы всегда возвращать True), однако, все мои попытки пока не увенчались успехом.

Я использую подход декоратора с mock.patch и перепробовал кучу разных целей, но я считаю, что должна быть правильной: @mock.patch('scuevals_api.resources.students.year_in_range', return_value=True)

Функция макета никогда не вызывается, как, например, она не корректна. Я тоже не получаю никаких ошибок.

Мое единственное оставшееся подозрение заключается в том, что это как-то связано с тем, что функция передается в fields.Int в качестве параметра (отсюда и название вопроса), но, на мой взгляд, это ни на что не должно влиять.

Я не знаю, где эта функция должна быть высмеяна?

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Благодаря объяснению Криса Ханта я нашел альтернативное решение. Это действительно изменяет код приложения, а не тестовый код, но если это приемлемо (что, вероятно, должно быть в наши дни, так как наличие тестируемого кода является высоким приоритетом), это действительно простое решение:

Невозможно смоделировать year_in_range, поскольку ссылка на исходную функцию сохраняется до того, как будет выполнено смоделирование. Поэтому «оберните» функцию, которую вы хотите смоделировать, другой функцией и передайте оболочку. Обертывание может быть сделано аккуратно и аккуратно, используя лямбда-функции:

def year_in_range(year):
    return datetime.now().year <= year <= datetime.now().year + 10


class StudentsResource(Resource):
    args = {
        'graduation_year': fields.Int(required=True, validate=lambda y: year_in_range(y)),
    }

    ...

Теперь, когда я высмеиваю year_in_range, как указано в вопросе, это будет работать. Причина в том, что теперь ссылка сохраняется в лямбда-функции, а не в исходную year_in_range (к которой не будет доступа, пока не будет запущена лямбда-функция, что будет во время теста).

0 голосов
/ 21 января 2019

К моменту исправления mock year_in_range уже слишком поздно. mock.patch импортирует модуль, указанный в предоставленной вами строке, и исправляет имя, указанное в модуле, так что оно ссылается на фиктивный объект - это не меняет принципиально сам объект функции. При импорте scuevals_api.resources.students будет выполнено тело класса StudentsResource и ссылка на исходный year_in_range, сохраненная в объекте StudentResource.args['graduation_year'], в результате чего имя year_in_range, ссылающееся на фиктивный объект, не имеет воздействие.

В этом конкретном случае у вас есть несколько вариантов:

  1. Предполагая, что вы пытаетесь протестировать некоторые функции, вместо того, чтобы пытаться year_in_range, вы можете заполнить базу данных (?) Данными, которые проверяют условие
  2. Вы можете исправить datetime.now, который будет вызван year_in_range
  3. Вы можете исправить элемент StudentResource.args['graduation_year'], в котором функция, переданная в validate, была сохранена.
...