Модульное тестирование ABC с вспомогательными функциями в Python - PullRequest
0 голосов
/ 04 мая 2018

Мне интересно, возможно ли изменить вспомогательные функции в тестовой среде на 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 версии определенных модулей, чего не происходит в производстве. среда. Это хорошая идея, или я должен оставить ее в первой версии для моей тестовой среды?

...