Мне интересно, возможно ли изменить вспомогательные функции в тестовой среде на Python. Мое приложение имеет следующую структуру:
app/
trader/
__init__.py
strategies/
__init__.py
base_strategy.py
util.py
models/
__init__.py
base_model.py
tests/
__init__.py
strategies/
__init__.py
stub_strategy.py
test_strategies.py
models/
__init__.py
stub_model.py
где каждый base_*.py
является абстрактным базовым классом, который наследуется в каждом файле stub_*.py
в каталоге tests. В моем файле util.py
есть вспомогательная функция, которая просматривает каталог trader/strategies/models
и регистрирует все доступные модели:
import inspect
from . import alpha_models
existing_alpha_models = []
alpha_model_dict = {}
for name, obj in inspect.getmembers(alpha_models):
if inspect.isclass(obj):
existing_alpha_models.append(name)
alpha_model_dict[name] = obj
Теперь к моей проблеме: в моем BaseTradingStrategy
-классе у меня есть метод, который использует список existing_alpha_models
, чтобы проверить, существует ли модель.
from abc import ABC, abstractmethod
from .util import existing_alpha_models
class BaseTradingStrategy(ABC):
"""BaseTrading Code comes here"""
@abstractmethod
def some_abs_method(self):
raise NotImplementedError
def register_model(self, model_name):
if model_name not in existing_alpha_models:
raise ValueError
Для модульного тестирования я создал классы-заглушки, которых нет в каталоге trader/strategies/models
, и поэтому они не зарегистрированы в списке existing_alpha_models
. Когда я хочу проверить функциональность ABC с помощью pytest, многие тесты не выполняются, поскольку метод, который проверяет доступность моделей, не выполняется. Простым решением было бы поместить классы-заглушки в каталог trader
моего приложения, но я бы предпочел, чтобы мой тестовый код был отделен от остальной части приложения. Я, вероятно, мог бы также сделать existing_alpha_models
свойством базового класса, но на самом деле я не вижу смысла в этом, кроме как сделать тесты успешными. Есть ли способ внедрить классы-заглушки в existing_alpha_models
для модульного тестирования, чтобы тест ABC не завершился неудачей без слишком большого изменения базового класса?
-------------- EDIT -------------------
Теперь у меня есть 2 рабочие версии моего тестового кода. Один использует версию @hoefling, где я просто добавляю alpha_models
в список existing_alpha_models
:
from tests.strategies import StubTradingStrategy
from tests.strategies.alpha_models import StubModel, StubModel2, StubModel3
from trader.strategies.util import existing_alpha_models
existing_alpha_models.extend(["StubModel", "StubModel2", "StubModel3"])
и одна версия, где я добавляю модели в модуль alpha_models
и перезагружаю 2 модуля:
import importlib
from trader.strategies import alpha_models
from tests.strategies.alpha_models import StubModel, StubModel2, StubModel3
setattr(alpha_models, "StubModel", StubModel)
setattr(alpha_models, "StubModel2", StubModel2)
setattr(alpha_models, "StubModel3", StubModel3)
from nutrader.strategies import util
import nutrader.strategies.base_strategy
importlib.reload(util)
importlib.reload(nutrader.strategies.base_strategy)
from tests.strategies import StubTradingStrategy
Преимущество второй версии заключается в том, что она позволяет мне на самом деле тестировать код util
, но также представляет потенциальные риски в моем тестовом коде, поскольку существует 2 версии определенных модулей, чего не происходит в производстве. среда. Это хорошая идея, или я должен оставить ее в первой версии для моей тестовой среды?