Odoo18-Base/odoo/tests/loader.py

123 lines
3.8 KiB
Python
Raw Normal View History

2025-01-06 10:57:38 +07:00
import importlib
import importlib.util
import inspect
import logging
import sys
import threading
from pathlib import Path
from unittest import case
from .. import tools
from .tag_selector import TagsSelector
from .suite import OdooSuite
from .result import OdooTestResult
_logger = logging.getLogger(__name__)
def get_module_test_cases(module):
"""Return a suite of all test cases contained in the given module"""
for obj in module.__dict__.values():
if not isinstance(obj, type):
continue
if not issubclass(obj, case.TestCase):
continue
if obj.__module__ != module.__name__:
continue
test_case_class = obj
test_cases = test_case_class.__dict__.items()
if getattr(test_case_class, 'allow_inherited_tests_method', False):
# keep iherited method for specific classes.
# This is likely to be removed once a better solution is found
test_cases = inspect.getmembers(test_case_class, callable)
else:
# sort test case to keep the initial behaviour.
# This is likely to be removed in the future
test_cases = sorted(test_cases, key=lambda pair: pair[0])
for method_name, method in test_cases:
if not callable(method):
continue
if not method_name.startswith('test'):
continue
yield test_case_class(method_name)
def get_test_modules(module):
""" Return a list of module for the addons potentially containing tests to
feed get_module_test_cases() """
results = _get_tests_modules(importlib.util.find_spec(f'odoo.addons.{module}'))
results += list(_get_upgrade_test_modules(module))
return results
def _get_tests_modules(mod):
spec = importlib.util.find_spec('.tests', mod.name)
if not spec:
return []
tests_mod = importlib.import_module(spec.name)
return [
mod_obj
for name, mod_obj in inspect.getmembers(tests_mod, inspect.ismodule)
if name.startswith('test_')
]
def _get_upgrade_test_modules(module):
upgrade_modules = (
f"odoo.upgrade.{module}",
f"odoo.addons.{module}.migrations",
f"odoo.addons.{module}.upgrades",
)
for module_name in upgrade_modules:
if not importlib.util.find_spec(module_name):
continue
upg = importlib.import_module(module_name)
for path in map(Path, upg.__path__):
for test in path.glob("tests/test_*.py"):
spec = importlib.util.spec_from_file_location(f"{upg.__name__}.tests.{test.stem}", test)
if not spec:
continue
pymod = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = pymod
spec.loader.exec_module(pymod)
yield pymod
def make_suite(module_names, position='at_install'):
""" Creates a test suite for all the tests in the specified modules,
filtered by the provided ``position`` and the current test tags
:param list[str] module_names: modules to load tests from
:param str position: "at_install" or "post_install"
"""
config_tags = TagsSelector(tools.config['test_tags'])
position_tag = TagsSelector(position)
tests = (
t
for module_name in module_names
for m in get_test_modules(module_name)
for t in get_module_test_cases(m)
if position_tag.check(t) and config_tags.check(t)
)
return OdooSuite(sorted(tests, key=lambda t: t.test_sequence))
def run_suite(suite):
# avoid dependency hell
from ..modules import module
module.current_test = True
threading.current_thread().testing = True
results = OdooTestResult()
suite(results)
threading.current_thread().testing = False
module.current_test = False
return results