Выполнение модульных тестов по вложенным функциям

Я исхожу из мира Java, где вы можете скрыть переменные и функции, а затем выполнить тесты модулей против них с помощью отражения. Я использовал вложенные функции, чтобы скрыть детали реализации моих классов, чтобы был видимым только публичный API. Я пытаюсь написать модульные тесты против этих вложенных функций, чтобы убедиться, что я не разбиваю их по мере развития. Я попытался вызвать одну из вложенных функций, таких как:

def outer(): def inner(): pass outer.inner() 

в результате чего появляется сообщение об ошибке:

AttributeError: объект 'function' не имеет атрибута 'inner'

Есть ли способ написать отдельные тесты против этих вложенных функций? Если нет, есть ли способ вызвать имя munging для имен функций, как вы можете для переменных класса, префикс их __?

6 Solutions collect form web for “Выполнение модульных тестов по вложенным функциям”

Соглашение Python должно называть «частные» функции и методы с лидирующим подчеркиванием. Когда вы видите лидирующий знак подчеркивания, вы не должны пытаться его использовать.

Помните, что Python – это не Java .

внутренний не существует, пока внешний не сделает это. Вы должны либо переместиться внутрь до функции верхнего уровня для проверки, либо иметь внешний тестовый тест всех возможных путей выполнения самого себя и внутреннего.

Обратите внимание, что внутренняя функция не является простой функцией, это закрытие. Рассмотрим этот случай:

 def outer(a): b = compute_something_from(a) def inner(): do_something_with(a, b) 

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

Невозможно получить внутреннюю функцию из внешнего объекта функции (см. Другие ответы!). Тем не менее, как модульные тесты, так и закрытие сделали (по крайней мере, для меня) удивительные улучшения производительности разработчиков. Можем ли мы оба? Можем ли мы изолировать изолированные вложенные функции?

Не легко.

Тем не менее, такое может быть достигнуто с использованием парсера модулей python, ast или токенизатора, чтобы выровнять сам код, извлекая внутренние функции (через некоторый путь через вложенность) и позволяя испытаниям запускать их с состоянием из закрывающих функций (значения для закрытых имен) и stubs / mocks для более вложенных функций (определенных в тестовой цели).

Кто-нибудь знает что-нибудь подобное? Google не смог найти ничего.

Я не думаю, что есть шанс получить доступ к inner () из пространства имен extern.

Однако, на мой взгляд, тот факт, что вы держите внутреннее () вложенное, подразумевает, что единственный «контракт», который действительно имеет значение, является внешним (). inner () является частью реализации, и вы не должны пытаться протестировать реализацию. Если вы действительно хотите протестировать inner (), выполните обширные тесты на external () с данными, которые будут включать в себя все функции inner ().

У меня были такие же сомнения, и я нашел способ получить тесты для внутренних функций.

 def outer(): def inner(): pass if __debug__: test_inner(inner) # return def test_inner(f): f() # this calls the inner function outer() 

В принципе, вы можете отправить внутреннюю функцию как параметр снаружи и протестировать ее по своему усмотрению. При вызове функции outer () ваш тест будет запущен, и поскольку это замыкание, он сохранит любое дополнительное свойство из внешней функции (например, переменных). Используя список, вы можете отправить столько функций, сколько пожелаете. Чтобы игнорировать if , нужно запустить такой код:

 python -O code.py 

Я написал небольшой вспомогательный модуль, который позволяет именно это:

Примеры вложенных функций:

 def f(v1): v2 = 1 def g(v3=2): return v1 + v2 + v3 + 4 def h(): return 16 return g() + h() + 32 class C(object): def foo(self): def k(x): return [ self, x ] return k(3) def m(): vm = 1 def n(an=2): vn = 4 def o(ao=8): vo = 16 return vm + an + vn + ao + vo return o() return n() 

Они могут быть протестированы с использованием этого типа кода:

 import unittest from nested import nested class TestNested(unittest.TestCase): def runTest(self): nestedG = nested(f, 'g', v1=8, v2=1) self.assertEqual(nestedG(2), 15) nestedH = nested(f, 'h') self.assertEqual(nestedH(), 16) nestedK = nested(C.foo, 'k', self='mock') self.assertEqual(nestedK(5), [ 'mock', 5 ]) nestedN = nested(m, 'n', vm=1) nestedO = nested(nestedN, 'o', vm=1, an=2, vn=4) self.assertEqual(nestedO(8), 31) def main(argv): unittest.main() if __name__ == '__main__': import sys sys.exit(main(sys.argv)) 

nested небольшой вспомогательный модуль выглядит следующим образом:

 import types def freeVar(val): def nested(): return val return nested.__closure__[0] def nested(outer, innerName, **freeVars): if isinstance(outer, (types.FunctionType, types.MethodType)): outer = outer.func_code for const in outer.co_consts: if isinstance(const, types.CodeType) and const.co_name == innerName: return types.FunctionType(const, globals(), None, None, tuple( freeVar(freeVars[name]) for name in const.co_freevars)) 
Python - лучший язык программирования в мире.