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

Как исправлять внутренние функции модуля с помощью макета?

Под "внутренней функцией" подразумевается функция, вызываемая из того же модуля, в которой она определена.

Я использую библиотеку mock, в частности, декораторы patch, в моем модуле тесты. Это модульные тесты Django, но это должно применяться к любым тестам python.

У меня есть один модуль с несколькими функциями, многие из которых называют друг друга. Например (фиктивный код, игнорировать отсутствие decimal.Decimal):

TAX_LOCATION = 'StateName, United States'

def add_tax(price, user):
    tax = 0
    if TAX_LOCATION == 'StateName, UnitedStates':
        tax = price * .75
    return (tax, price+tax)

def build_cart(...):
    # build a cart object for `user`
    tax, price = add_tax(cart.total, cart.user)
    return cart

Это часть более глубокой вызывающей цепочки (func1 → func2 → build_cart → add_tax), все из которых находятся в одном модуле.

В моих модульных тестах я хотел бы отключить налоги, чтобы получить согласованные результаты. Как я вижу, мои два варианта: 1) исправить TAX_LOCATION (с пустой строкой, скажем), чтобы add_tax ничего не делал или 2) исправил add_tax, чтобы просто вернуть (0, цена).

Однако, когда я пытаюсь установить патч, патч работает внешне (я могу импортировать исправленную часть внутри теста и распечатать его, получить ожидаемые значения), но, кажется, не оказывает внутреннего эффекта (результаты я get from code ведут себя так, как если бы патч не применялся).

Мои тесты подобны этому (опять же, фиктивный код):

from mock import patch
from django.test import TestCase

class MyTests(TestCase):

    @patch('mymodule.TAX_LOCATION', '')
    def test_tax_location(self):
        import mymodule
        print mymodule.TAX_LOCATION # ''
        mymodule.func1()
        self.assertEqual(cart.total, original_price) # fails, tax applied

    @patch('mymodule.add_tax', lambda p, u: (0, p))
    def test_tax_location(self):
        import mymodule
        print mymodule.add_tax(50, None) # (0, 50)
        mymodule.func1()
        self.assertEqual(cart.total, original_price) # fails, tax applied

Кто-нибудь знает, может ли макет исправлять функции, используемые внутри, например, или мне не повезло?

4b9b3361

Ответ 1

Ответ: Очистить свой проклятый импорт

@patch('mymodule.TAX_LOCATION', '') действительно исправлял вещи должным образом, но поскольку наш импорт в то время был очень случайным - иногда мы импортировали mymodule.build_cart, иногда мы импортировали project.mymodule.build_cart - экземпляры "полного" импорта не были исправлены на все. В любом случае, Mock не может знать о двух отдельных путях импорта... без всякого объяснения.

Мы с тех пор стандартизировали весь наш импорт на более длинном пути, и сейчас все выглядит лучше.

Ответ 2

другой вариант заключается в явном вызове patch для функции:

mock.patch('function_name')

и поддерживать как запущенные напрямую, так и из py.test и т.д.:

mock.patch(__name__ + '.' + 'function_name')

Ответ 3

Я уверен, что ваша проблема заключается в том, что вы импортируете 'mymodule' внутри своих тестовых функций, и поэтому у декоратора исправления нет никаких шансов на исправление. Сделайте импорт в верхней части модуля, как и любой другой импорт.