Як правильно обробити глобальні параметри для тестування одиниць у 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

Чи є кращий спосіб, який менш схильний, але все ж пропонує гнучкість для тестування одиниць? Це справді найкраща практика?

Відповіді:


1

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

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


0

Ви можете зробити ряд речей.

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

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

Звичайно, будь-який із цих варіантів багато працює, але ви не запитаєте, чи це не для вас проблема.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.