Если вы пишете библиотеку или приложение, куда деваются файлы модульного теста?
Приятно отделить тестовые файлы от основного кода приложения, но неудобно помещать их в подкаталог «tests» внутри корневого каталога приложения, поскольку это затрудняет импорт модулей, которые вы будете тестировать.
Есть ли здесь лучшая практика?






Я не верю, что существует устоявшаяся «лучшая практика».
Я помещаю свои тесты в другой каталог вне кода приложения. Затем я добавляю основной каталог приложения в sys.path (позволяющий импортировать модули из любого места) в свой сценарий запуска тестов (который также выполняет некоторые другие действия) перед запуском всех тестов. Таким образом, мне никогда не придется удалять каталог тестов из основного кода при его выпуске, что экономит мое время и усилия, пусть даже и очень незначительные.
Вот как это выглядит для меня: os.sys.path.append(os.dirname('..'))
Распространенной практикой является размещение каталога тестов в том же родительском каталоге, что и ваш модуль / пакет. Итак, если бы ваш модуль назывался foo.py, макет вашего каталога выглядел бы так:
parent_dir/
foo.py
tests/
Конечно, нет единого способа сделать это. Вы также можете создать подкаталог tests и импортировать модуль с помощью абсолютный импорт.
Где бы вы ни разместили свои тесты, я бы рекомендовал вам использовать нос для их запуска. Нос ищет тесты в ваших каталогах. Таким образом, вы можете размещать тесты там, где они наиболее целесообразны с организационной точки зрения.
Я бы хотел это сделать, но не могу заставить это работать. Чтобы запустить тесты, я нахожусь в parent_dir и набираю: "python tests \ foo_test.py", а в foo_test.py: "из ..foo импортируйте это, это, другое" Это не удается с: "ValueError: Attempted относительный импорт без пакета "И parent_dir, и тесты содержат в этом.py, поэтому я не уверен, почему они не являются пакетами. Я подозреваю, что это потому, что сценарий верхнего уровня, который вы запускаете из командной строки, не может считаться (частью) пакета, даже если он находится в каталоге с в этом.py. Итак, как мне запустить тесты? Я сегодня работаю над Windows, благослови мои хлопковые носки.
Лучший способ - я нашел - запускать модульные тесты - это установить вашу библиотеку / программу, а затем запускать модульные тесты с носом. Я бы порекомендовал virtualenv и virtualenvwrapper, чтобы сделать это намного проще.
@Tartley - вам нужен файл в этом.py в вашем каталоге «tests» для работы импорта Absolution. У меня есть этот метод для работы с носом, поэтому я не уверен, почему у вас проблемы.
Спасибо, Кейси, но у меня есть файл в этом.py во всех соответствующих каталогах. Я не знаю, что я делаю не так, но у меня есть эта проблема во всех моих проектах Python, и я не могу понять, почему никто другой не делает. О боже.
Одно из решений моей проблемы с Python2.6 или новее: запускать тесты из корня вашего проекта, используя: python -m project.package.tests.module_tests (вместо python project / package / tests / module_tests.py) . Это помещает каталог тестового модуля в путь, поэтому тесты могут затем выполнить относительный импорт в свой родительский каталог, чтобы получить тестируемый модуль.
nose и nose2 находятся в режиме обслуживания. С веб-сайта nose: Nose находится в режиме обслуживания в течение последних нескольких лет и, вероятно, прекратит работу без нового человека / команды, которые возьмут на себя поддержку. В новых проектах следует рассмотреть возможность использования Nose2, py.test или просто unittest / unittest2.
из nose2 github (github.com/nose-devs/nose2): Несмотря на то, что плагины unittest2 так и не появились, нос2 все еще поддерживается! У нас есть небольшое сообщество, заинтересованное в продолжении работы и использования носа2. Однако, учитывая текущую ситуацию, когда к pytest проявляется гораздо больший интерес, ноу2 уделяет приоритетное внимание исправлениям ошибок и обслуживанию перед разработкой новых функций.
Так что, если вы еще не используете nose / nose2, возможно, лучше использовать py.test.
Я недавно начал программировать на Python, так что у меня еще не было возможности узнать о лучших практиках. Но я написал модуль, который находит все тесты и запускает их.
Так что я:
app/ appfile.py test/ appfileTest.py
Мне нужно будет посмотреть, как это будет происходить, когда я перейду к более крупным проектам.
Привет, CamelCase - это немного странно в мире питонов.
Я использую каталог tests/, а затем импортирую основные модули приложения, используя относительный импорт. Итак, в MyApp / tests / foo.py может быть:
from .. import foo
для импорта модуля MyApp.foo.
"ValueError: Попытка относительного импорта не в пакете"
В C# я обычно выделяю тесты в отдельную сборку.
В Python - до сих пор - я имел тенденцию либо писать тесты, где тест находится в строке документации функции, либо помещать их в блок if __name__ == "__main__" в нижней части модуля.
Для файла module.py модульный тест обычно должен называться test_module.py в соответствии с соглашениями об именах Pythonic.
Есть несколько общепринятых мест для размещения test_module.py:
module.py.../tests/test_module.py (на том же уровне, что и каталог кода).tests/test_module.py (один уровень под каталогом кода).Я предпочитаю №1 из-за простоты поиска тестов и их импорта. Какую бы систему сборки вы ни использовали, ее можно легко настроить для запуска файлов, начиная с test_. Собственно, файл шаблон unittest по умолчанию, используемый для обнаружения тестов - test*.py.
протокол load_tests по умолчанию ищет файлы с именем test * .py. Кроме того, этот лучший результат Google и эта документация unittest используют формат test_module.py.
Использование foo_test.py может сэкономить нажатие одной или двух клавиш при использовании завершения по табуляции, поскольку у вас нет группы файлов, начинающихся с 'test_'.
@juniper, следуя вашим мыслям, module_test будет отображаться в автозавершении, когда вы пишете код. Это может сбивать с толку или раздражать.
При развертывании кода мы не хотим развертывать тесты в наших производственных местах. Таким образом, размещение их в одном каталоге './tests/test_blah.py' легко изменить при развертывании. ТАКЖЕ, некоторые тесты берут образцы файлов данных, и наличие их в тестовом каталоге жизненно важно, чтобы мы не развертывали тестовые данные.
@ KevinJ.Rice Разве вы не должны проверять, работает ли код на ваших производственных площадках?
@endolith, Не работает тестовый код (функциональное тестирование) на prod box, только запускает тесты на dev и QA и, возможно, промежуточные ящики, если они у нас есть. Ящики продуктов заблокированы и имеют доступ к производственным базам данных и т. д., А тесты могут случайно получить доступ к этой критически важной инфраструктуре. Лучше не включать тесты в продукты, если вы не пытаетесь сделать что-то очень конкретное, например, службы мониторинга, в этом случае мы говорим о мониторинге, а не о модульных тестах.
Предполагается ли, что путь к модулю уже был добавлен в Python, чтобы вы могли импортировать модуль в свои файлы тестирования?
Я считаю весьма полезным отправлять тесты в основной каталог модуля, так как это позволяет мне отправлять код в производство (если я хочу!), Что позволяет пользователям запускать набор тестов непосредственно перед тем, как регистрировать ошибки ...
При написании пакета под названием «foo» я помещу модульные тесты в отдельный пакет «foo_test». Модули и подпакеты будут иметь то же имя, что и модуль пакета SUT. Например. тесты для модуля foo.x.y находятся в foo_test.x.y. Файлы __init__.py каждого пакета тестирования затем содержат набор AllTests, который включает все наборы тестов пакета. setuptools предоставляет удобный способ указать основной пакет тестирования, так что после «python setup.py develop» вы можете просто использовать «python setup.py test» или «python setup.py test -s foo_test.x.SomeTestSuite» для просто конкретный сюит.
Если тесты простые, просто поместите их в строку документации - большинство тестовых фреймворков для Python смогут это использовать:
>>> import module
>>> module.method('test')
'testresult'
Для других более сложных тестов я бы поместил их либо в ../tests/test_module.py, либо в tests/test_module.py.
Я также стараюсь помещать свои модульные тесты в сам файл, как отмечает Джереми Кантрелл выше, хотя я стараюсь не помещать тестовую функцию в основное тело, а скорее помещаю все в
if __name__ == '__main__':
do tests...
блокировать. В итоге в файл добавляется документация в виде «примера кода» для использования тестируемого файла python.
Должен добавить, что я обычно пишу очень плотные модули / классы. Если для ваших модулей требуется очень большое количество тестов, вы можете поместить их в другой, но даже в этом случае я бы все равно добавил:
if __name__ == '__main__':
import tests.thisModule
tests.thisModule.runtests
Это позволяет любому, кто читает ваш исходный код, знать, где искать тестовый код.
"как отмечает Джереми Кантрелл" где?
Мне нравится такой способ работы. Самый простой из редакторов может быть настроен для запуска вашего файла с помощью горячей клавиши, поэтому, когда вы просматриваете код, вы можете мгновенно запускать тесты. К сожалению, на языках, отличных от Python, это может выглядеть ужасно, поэтому, если вы работаете в магазине C++ или Java, ваши коллеги могут это осудить. Это также плохо работает с инструментами покрытия кода.
Мы используем
app/src/code.py
app/testing/code_test.py
app/docs/..
В каждый тестовый файл мы вставляем ../src/ в sys.path. Это не самое лучшее решение, но оно работает. Я думаю, было бы здорово, если бы кто-то придумал что-то вроде maven в java, которое дает вам стандартные соглашения, которые просто работают, независимо от того, над каким проектом вы работаете.
Я предпочитаю каталог тестов верхнего уровня. Это означает, что импорт становится немного сложнее. Для этого у меня есть два решения:
test_suite='tests.runalltests.suite' в setup() и просто запустить тесты: python setup.py testPYTHONPATH=. python tests/runalltests.pyВот как это поддерживается кодом в M2Crypto:
Если вы предпочитаете проводить тесты с помощью носовых тестов, возможно, вам нужно сделать что-то другое.
Тот же вопрос возник у нас при написании Pythoscope (https://pypi.org/project/pythoscope/), который генерирует модульные тесты для программ Python. Перед тем, как выбрать каталог, мы опросили людей о тестировании в списке Python, было много разных мнений. В конце концов, мы решили поместить каталог «tests» в тот же каталог, что и исходный код. В этом каталоге мы генерируем тестовый файл для каждого модуля в родительском каталоге.
Потрясающие! Просто запустил Pythoscope (отличный логотип) на каком-то устаревшем коде, и это было потрясающе. Мгновенные передовые методы, и вы можете заставить других разработчиков заполнить уже неуспешные тестовые заглушки. А теперь подключить его к бамбуку? :)
Как я это делаю ...
Структура папки:
project/
src/
code.py
tests/
setup.py
Setup.py указывает на src / как расположение, содержащее модули моих проектов, затем я запускаю:
setup.py develop
Что добавляет мой проект в пакеты сайтов, указывая на мою рабочую копию. Для запуска своих тестов я использую:
setup.py tests
Используя тот тестовый раннер, который я настроил.
Кажется, вы отказались от термина «модуль». Большинство программистов Python, вероятно, подумают, что модуль - это файл, который вы назвали code.py. Было бы разумнее назвать каталог верхнего уровня «проектом».
Исходя из моего опыта разработки фреймворков тестирования на Python, я бы посоветовал поместить модульные тесты Python в отдельный каталог. Поддерживайте симметричную структуру каталогов. Это было бы полезно для упаковки только основных библиотек, а не для упаковки модульных тестов. Ниже реализована принципиальная схема.
<Main Package>
/ \
/ \
lib tests
/ \
[module1.py, module2.py, [ut_module1.py, ut_module2.py,
module3.py module4.py, ut_module3.py, ut_module.py]
__init__.py]
Таким образом, когда вы упаковываете эти библиотеки с помощью rpm, вы можете просто упаковать модули основной библиотеки (только). Это способствует удобству обслуживания, особенно в гибкой среде.
Я понял, что одним из потенциальных преимуществ этого подхода является то, что тесты могут быть разработаны (и, возможно, даже с контролем версий) как самостоятельные приложения. Конечно, у каждого преимущества есть свой недостаток - поддержание симметрии в основном сводится к «двойному учету» и делает рефакторинг более утомительным.
Мягкий дополнительный вопрос: почему гибкая среда особенно хорошо подходит для этого подхода? (т.е. что в гибком рабочем процессе делает симметричную структуру каталогов такой выгодной?)
Если имеется только 1 тестовый файл, рекомендуется поместить его в каталог верхнего уровня:
module/
lib/
__init__.py
module.py
test.py
Запустить тест в CLI
python test.py
Если у вас много тестовых файлов, поместите его в папку tests:
module/
lib/
__init__.py
module.py
tests/
test_module.py
test_module_function.py
# test_module.py
import unittest
from lib import module
class TestModule(unittest.TestCase):
def test_module(self):
pass
if __name__ == '__main__':
unittest.main()
Запустить тест в CLI
# In top-level /module/ folder
python -m tests.test_module
python -m tests.test_module_function
unittest discoveryunittest discovery найдет все тесты в папке пакета.
Создайте __init__.py в папке tests/
module/
lib/
__init__.py
module.py
tests/
__init__.py
test_module.py
test_module_function.py
Запустить тест в CLI
# In top-level /module/ folder
# -s, --start-directory (default current directory)
# -p, --pattern (default test*.py)
python -m unittest discover
Я рекомендую вам проверить некоторые основные проекты Python на GitHub и почерпнуть некоторые идеи.
Когда ваш код становится больше и вы добавляете больше библиотек, лучше создать тестовую папку в том же каталоге, что и у вас setup.py, и отразить структуру каталогов вашего проекта для каждого типа теста (unittest, интеграция, ...)
Например, если у вас есть такая структура каталогов:
myPackage/
myapp/
moduleA/
__init__.py
module_A.py
moduleB/
__init__.py
module_B.py
setup.py
После добавления тестовой папки у вас будет такая структура каталогов, как:
myPackage/
myapp/
moduleA/
__init__.py
module_A.py
moduleB/
__init__.py
module_B.py
test/
unit/
myapp/
moduleA/
module_A_test.py
moduleB/
module_B_test.py
integration/
myapp/
moduleA/
module_A_test.py
moduleB/
module_B_test.py
setup.py
Многие правильно написанные пакеты Python используют ту же структуру. Очень хороший пример - пакет Boto. Проверить https://github.com/boto/boto
Рекомендуется использовать «тесты» вместо «test», потому что «test» - это встроенный модуль Python. docs.python.org/2/library/test.html
Не всегда .. например matplotlib имеет его под matplotlib/lib/matplotlib/tests (github.com/matplotlib/matplotlib/tree/…), sklearn имеет его под scikitelearn/sklearn/tests (github.com/scikit-learn/scikit-learn/tree/master/sklearn/te sts)
Время от времени я обнаруживаю, что проверяю тему размещения тестов, и каждый раз большинство рекомендует отдельную структуру папок рядом с кодом библиотеки, но я обнаруживаю, что каждый раз аргументы одинаковы и не так убедительны. В итоге я кладу свои тестовые модули где-нибудь рядом с основными модулями.
Основная причина для этого: рефакторинг.
Когда я что-то перемещаю, я действительно хочу, чтобы тестовые модули двигались вместе с кодом; легко потерять тесты, если они находятся в отдельном дереве. Давайте будем честными, рано или поздно вы получите совершенно другую структуру папок, такую как джанго, фляга и многие другие. Что нормально, если тебе все равно.
Главный вопрос, который вы должны себе задать:
Я пишу:
Если:
Отдельная папка и дополнительные усилия по поддержанию ее структуры могут подойти лучше. Никто не будет жаловаться на то, что ваши тесты получат развернут в производство.
Но также легко исключить тесты из распространения, если они смешаны с основными папками; поместите это в setup.py:
find_packages("src", exclude=["*.tests", "*.tests.*", "tests.*", "tests"])
Если b:
Вы можете пожелать - как и каждый из нас - чтобы вы писали многоразовые библиотеки, но большую часть времени их жизнь связана с жизнью проекта. Умение легко поддерживать ваш проект должно быть приоритетом.
Затем, если вы хорошо поработали и ваш модуль хорошо подходит для другого проекта, он, вероятно, будет скопирован - а не разветвлен и не превращен в отдельную библиотеку - в этот новый проект, а тесты, которые лежат рядом с ним, будут перемещены в ту же структуру папок. это просто по сравнению с поиском тестов в беспорядке, который превратился в отдельную папку с тестами. (Вы можете возразить, что здесь не должно быть беспорядка, но давайте будем реалистами).
Так что выбор по-прежнему за вами, но я бы сказал, что с помощью смешанных тестов вы достигнете тех же результатов, что и с отдельной папкой, но с меньшими усилиями по поддержанию порядка.
в чем вообще проблема с развертыванием тестов в продакшн? по моему опыту, это очень полезно: позволяет пользователям фактически запускать тесты в своей среде ... когда вы получаете отчеты об ошибках, вы можете попросить пользователя запустить набор тестов, чтобы убедиться, что там все в порядке, и отправить горячие патчи для теста suite напрямую ... кроме того, буду не из-за того, что вы помещаете свои тесты в module.tests, попадает в производство, если вы не сделали что-то не так в своем установочном файле ...
Как я уже писал в своем ответе, я обычно не разделяю тесты. Но. Включение тестов в дистрибутив может привести к выполнению вещей, которые обычно не нужны в производственной среде (например, некоторый код уровня модуля). Это, конечно, зависит от того, как написаны тесты, но на всякий случай, если вы их оставите, никто не запустит что-то вредоносное по ошибке. Я не против включения тестов в дистрибутивы, но понимаю, что, как правило, это безопаснее. А размещение их в отдельной папке позволяет очень легко не включать их в dist.
Я помещаю свои тесты в тот же каталог, что и тестируемый код (CUT); для foo.py тесты будут проводиться в foo_ut.py или аналогичном. (Я настраиваю процесс обнаружения тестов, чтобы найти их.)
Это помещает тесты рядом с кодом в список каталогов, делая очевидным, что тесты есть, и делает открытие тестов настолько простым, насколько это возможно, когда они находятся в отдельном файле. (Для редакторов командной строки, vim foo* и при использовании графического браузера файловой системы просто щелкните файл CUT, а затем непосредственно соседний тестовый файл.)
Как и другие указали, это также упрощает рефакторинг и извлечение кода для использования в другом месте, если это когда-либо понадобится.
Мне очень не нравится идея размещать тесты в совершенно другом дереве каталогов; зачем делать разработчикам сложнее, чем необходимо, открывать тесты, когда они открывают файл с помощью CUT? Не похоже, что подавляющее большинство разработчиков настолько увлечены написанием или настройкой тестов, что они игнорируют любые препятствия для этого, вместо того, чтобы использовать барьер в качестве оправдания. (По моему опыту, как раз наоборот; даже если вы делаете это как можно проще, я знаю многих разработчиков, которым не нужно писать тесты.)