Coverage for adhoc-cicd-odoo-odoo / odoo / tests / loader.py: 98%

68 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-09 18:05 +0000

1import importlib 

2import importlib.util 

3import inspect 

4import logging 

5import sys 

6from pathlib import Path 

7from unittest import case 

8 

9from .. import tools 

10from .tag_selector import TagsSelector 

11from .suite import OdooSuite 

12from .result import OdooTestResult 

13 

14 

15_logger = logging.getLogger(__name__) 

16 

17 

18def get_module_test_cases(module): 

19 """Return a suite of all test cases contained in the given module""" 

20 for obj in module.__dict__.values(): 

21 if not isinstance(obj, type): 

22 continue 

23 if not issubclass(obj, case.TestCase): 

24 continue 

25 if obj.__module__ != module.__name__: 

26 continue 

27 

28 test_case_class = obj 

29 test_cases = test_case_class.__dict__.items() 

30 if getattr(test_case_class, 'allow_inherited_tests_method', False): 

31 # keep iherited method for specific classes. 

32 # This is likely to be removed once a better solution is found 

33 test_cases = inspect.getmembers(test_case_class, callable) 

34 else: 

35 # sort test case to keep the initial behaviour. 

36 # This is likely to be removed in the future 

37 test_cases = sorted(test_cases, key=lambda pair: pair[0]) 

38 

39 for method_name, method in test_cases: 

40 if not callable(method): 

41 continue 

42 if not method_name.startswith('test'): 

43 continue 

44 yield test_case_class(method_name) 

45 

46 

47def get_test_modules(module): 

48 """ Return a list of module for the addons potentially containing tests to 

49 feed get_module_test_cases() """ 

50 results = _get_tests_modules(importlib.util.find_spec(f'odoo.addons.{module}')) 

51 results += list(_get_upgrade_test_modules(module)) 

52 

53 return results 

54 

55 

56def _get_tests_modules(mod): 

57 spec = importlib.util.find_spec('.tests', mod.name) 

58 if not spec: 

59 return [] 

60 

61 tests_mod = importlib.import_module(spec.name) 

62 return [ 

63 mod_obj 

64 for name, mod_obj in inspect.getmembers(tests_mod, inspect.ismodule) 

65 if name.startswith('test_') 

66 ] 

67 

68 

69def _get_upgrade_test_modules(module): 

70 upgrade_modules = ( 

71 f"odoo.upgrade.{module}", 

72 f"odoo.addons.{module}.migrations", 

73 f"odoo.addons.{module}.upgrades", 

74 ) 

75 for module_name in upgrade_modules: 

76 if not importlib.util.find_spec(module_name): 

77 continue 

78 

79 upg = importlib.import_module(module_name) 

80 for path in map(Path, upg.__path__): 

81 for test in path.glob("tests/test_*.py"): 

82 spec = importlib.util.spec_from_file_location(f"{upg.__name__}.tests.{test.stem}", test) 

83 if not spec: 83 ↛ 84line 83 didn't jump to line 84 because the condition on line 83 was never true

84 continue 

85 pymod = importlib.util.module_from_spec(spec) 

86 sys.modules[spec.name] = pymod 

87 spec.loader.exec_module(pymod) 

88 yield pymod 

89 

90 

91def make_suite(module_names, position='at_install'): 

92 """ Creates a test suite for all the tests in the specified modules, 

93 filtered by the provided ``position`` and the current test tags 

94 

95 :param list[str] module_names: modules to load tests from 

96 :param str position: "at_install" or "post_install" 

97 """ 

98 config_tags = TagsSelector(tools.config['test_tags']) 

99 position_tag = TagsSelector(position) 

100 tests = ( 

101 t 

102 for module_name in module_names 

103 for m in get_test_modules(module_name) 

104 for t in get_module_test_cases(m) 

105 if position_tag.check(t) and config_tags.check(t) 

106 ) 

107 return OdooSuite(sorted(tests, key=lambda t: getattr(t, 'test_sequence', 0))) 

108 

109 

110def run_suite(suite, global_report=None): 

111 # avoid dependency hell 

112 from ..modules import module 

113 module.current_test = True 

114 

115 results = OdooTestResult(global_report=global_report) 

116 suite(results) 

117 

118 module.current_test = False 

119 return results