Могу ли я поместить определения шагов в папку, которая не является "шаги" с поведением?
Я пытаюсь работать с Behave на Python. Мне было интересно, есть ли способ поместить мои файлы.py в другое место, вместо того, чтобы заставлять их все помещать в папку "steps". Моя текущая структура будет выглядеть так
tests/
features/
steps/ #all code inside here, for now
То, что я хотел бы достичь, это что-то вроде
tests/
features/ #with all the .feature files
login/ #with all the .py files for logging in inside a service
models/ #with all the .py files that represents a given object
and so on
Единственной платформой BDD, которую я использовал до Behave, был Cucumber с Java, который позволял вставлять определения шагов везде, где я хотел (а остальное обрабатывал сам Cucumber). Я спрашиваю об этом, потому что мне бы хотелось, чтобы в моем проекте было много классов, чтобы лучше организовать свой код.
4 ответа
Во-первых, из поведенческой документации (выпуск 1.2.7.dev0):
Поведение работает с тремя типами файлов:
- файлы функций, написанные вашим бизнес-аналитиком / спонсором / кем бы то ни было с вашими сценариями поведения в нем, и
- каталог "steps" с реализациями шагов Python для сценариев.
- по желанию некоторые элементы управления средой (код для запуска до и после шагов, сценарии, функции или весь матч по стрельбе).
Так что steps/
каталог требуется.
Чтобы выполнить обходной путь, аналогичный тому, что вы имеете в виду, я попытался создать подкаталог в /steps
каталог: /steps/deeper/
и вставил туда мой файл Python: /steps/deeper/testing.py
, После запуска поведения я получил "NotImplementedError", то есть определения шагов в /deeper/testing.py
не были найдены.
Похоже, что поведение не ищет рекурсивно через подкаталоги steps/
каталог для любых дополнительных файлов Python.
Что касается того, что вы пытаетесь сделать, я думаю, что это хорошая организационная идея, но, поскольку это невозможно, вы можете сделать это: вместо того, чтобы иметь каталоги для файлов Python в вашем tests/
каталог, почему бы не иметь хорошее соглашение об именовании для вашего файла Python и разделить связанные функции в свои собственные файлы Python? То есть:
tests/
features/
steps/
login_prompt.py # contains all the functions for logging in inside a service
login_ssh.py # contains all the functions for SSH login
models_default.py # contains all the functions for the default object
models_custom.py # contains all the functions for a custom object
and so on...
Конечно, на данный момент, это действительно не имеет значения, если вы разделяете их на разные файлы Python, так как ведет себя поиск по всем файлам Python в steps/
когда вызвано, но ради организации, это достигает того же самого эффекта.
Это может быть немного поздно, но вы можете сделать следующее:
Иметь такую структуру:
tests/
features/
steps/
login
main_menu
all_steps.py
В подпапках по шагам вы можете создать свой файл _steps.py с реализацией, а затем в файле all_steps.py(или как вы хотите его назвать) вам просто нужно импортировать их:
from tests.steps.login.<feature>_step import *
from tests.steps.main_menu.<feature>_step import *
etc
И когда вы запустите это, он должен найти файлы шагов. В качестве альтернативы вы можете хранить файлы в любом месте проекта, если у вас есть папка 1 Шаги и файл в файле, где вы импортировали все шаги
Вы можете сделать это с помощью дополнительного метода, например:
def import_steps_from_subdirs(dir_path):
for directory in walk(dir_path):
current_directory = directory[0] + '/'
all_modules = [module_info[1] for module_info in iter_modules(path=[current_directory])]
current_directory = current_directory.replace(Resources.BASE_DIR + '/', '')
for module in all_modules:
import_module(current_directory.replace('/', '.') + module)
Затем вызовите этот метод в слое before_all.
я усыновилBidonus'
следующее решение, оно должно быть доступно для копирования/вставки:
features/helpers/import_helper.py
from importlib import import_module
from pkgutil import iter_modules
from os import walk
from pathlib import Path
def import_steps(steps_dir: Path):
assert steps_dir.exists()
for (directory, _, _) in walk(steps_dir):
if "__pycache__" in directory:
continue
if directory == str(steps_dir):
continue
current_directory = directory + "/"
print(f"Importing Additional Steps: {current_directory}")
all_modules = [module_info[1]
for module_info in iter_modules(path=[str(current_directory)])]
current_directory = current_directory.replace(str(steps_dir) + '/', '')
for module in all_modules:
module_path = current_directory.replace('/', '.') + module
import_module(module_path)
Затем создал__init__.py
файл:
features/steps/__init__.py
from features.helpers.import_steps import import_steps
from pathlib import Path
STEPS_DIR_NAME = "steps"
STEPS_DIR = Path(__file__).parent
assert STEPS_DIR.name == STEPS_DIR_NAME
import_steps(STEPS_DIR)
Теперь, когда я запускаю свои тесты, у меня сначала есть:
Importing Additional Steps: /workspaces/XXXXX/features/steps/create_model/
Importing Additional Steps: /workspaces/XXXXX/features/steps/list_operations/
Importing Additional Steps: /workspaces/XXXXX/features/steps/assertions/
Importing Additional Steps: /workspaces/XXXXX/features/steps/assertions/list_assertions/
Importing Additional Steps: /workspaces/XXXXX/features/steps/context_managers/
Importing Additional Steps: /workspaces/XXXXX/features/steps/type_switchers/
Importing Additional Steps: /workspaces/XXXXX/features/steps/test_setup/
Importing Additional Steps: /workspaces/XXXXX/features/steps/dao_function_callers/
…
Test Results
…