Odoo18-Base/odoo/tests/loader.py
2025-01-06 10:57:38 +07:00

123 lines
3.8 KiB
Python

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