Как правильно обрабатывать глобальные параметры для модульного тестирования в python?

11

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

В настоящее время мы просто используем класс, содержащий все параметры и два предопределенных глобальных объекта:

class PublicParams(object):
    p = q = 0

    def __init__(self, p, q):
        self.p = p
        self.q = q

# used for tests
publicParams_test = PublicParams(15,7)               

# Some 2048 bit numbers for example
publicParams_secure = PublicParams(128378947298374928374,128378947298374928374)  

Затем алгоритмы принимают PublicParamsобъект в качестве аргумента, который по умолчанию является продуктивнымpublicParams_secure

def AlgoOne(n, publicParams = publicParams_secure):
    # do stuff with publicParams.p
    # ...
    AlgoTwo(x, publicParams)

и

def AlgoTwo(x, publicParams= publicParams_secure):
    # do stuff with publicParams.q

Таким образом, мы все еще можем ввести различные общедоступные параметры для упрощения модульного тестирования:

class AlgoOneTest(unittest.TestCase):
    def test(self):
        # compare with manually computed result
        self.assertTrue(AlgoOne(1, publicParams_test) == 10) 

Что мне не нравится в этом подходе:

  • Задание значения по publicParamsумолчанию делает его необязательным при вызове некоторого алгоритма. Однако становится легко забыть передать его при вызове AlgoTwoизнутри AlgoOne, что приведет к использованию двух разных объектов, если тестовый объект был переданAlgoOne

Есть ли лучший способ, который менее подвержен, но все же предлагает гибкость для модульного тестирования? Это действительно лучшая практика?

netik
источник

Ответы:

1

Создать конфигурационные файлы test_config.pyи production_config.py. Выберите один из них, используя переменную среды или аргумент командной строки. Импортируйте его (или читайте / анализируйте, если вы выберете .json/ .txtвместо .py) и сделайте результат доступным для всей программы через глобальный объект в модуле, который вы можете импортировать в любом месте.

Это очень похоже на то, что вы уже делаете, за исключением того, что оно продвигается на один шаг дальше, от глобальной области видимости до оболочки, из которой вы вызываете python. Преимущество состоит в том, что больше нет риска случайного смешения производственной и тестовой конфигурации: вы не можете прочитать оба файла в одном сеансе Python, поскольку существует только одна переменная среды / командная строка.

Максимум
источник
0

Есть несколько вещей, которые вы можете сделать.

  • Прекратите использовать глобалы
  • Прекратить использование значений по умолчанию
  • Всегда проверяйте через частные вспомогательные методы, которые не позволяют использовать значения по умолчанию

    def _AlgoOne(n, publicParams):
        return AlgoOne(n, publicParams)

Конечно, любой из этих вариантов - большая работа, но вы не спросите, не было ли это проблемой для вас.

candied_orange
источник
0

Всегда можно отделить коллекцию значений от глобального контекста и обработку этих параметров.

def do_the_thing():
    """Provides the public (rather untestable) context.
    _do_the_thing(global1, global2, publicParams)"""

def _do_the_thing(blah, blah, blah):
    "Actually does the thing"
    pass
user166988
источник