80 lines
2.7 KiB
Python
80 lines
2.7 KiB
Python
import importlib
|
|
import unittest
|
|
from collections import deque
|
|
from pathlib import Path
|
|
|
|
import frappe
|
|
from frappe.modules.utils import get_module_name
|
|
from frappe.testing.config import TestParameters
|
|
|
|
|
|
class FrappeTestLoader(unittest.TestLoader):
|
|
def recursive_load_suites_in_pymodule(self, suite):
|
|
suites_queue = deque([suite])
|
|
while suites_queue:
|
|
suite = suites_queue.popleft()
|
|
for elem in suite:
|
|
if elem.countTestCases():
|
|
if isinstance(elem, unittest.TestSuite):
|
|
suites_queue.append(elem)
|
|
elif isinstance(elem, unittest.TestCase):
|
|
if self.params.tests:
|
|
if elem._testMethodName in self.params.tests:
|
|
self.testsuite.addTest(elem)
|
|
else:
|
|
self.testsuite.addTest(elem)
|
|
|
|
def load_testsuites_in_pymodule(self, file_modules):
|
|
for module in file_modules:
|
|
suite = unittest.defaultTestLoader.loadTestsFromModule(module)
|
|
self.recursive_load_suites_in_pymodule(suite)
|
|
|
|
def load_pymodule_for_files(self, files: list):
|
|
"""
|
|
files: list of tuple of (Path, str)
|
|
"""
|
|
_file_modules = []
|
|
for app_path, test_file in files:
|
|
module_name = f"{'.'.join(test_file.relative_to(app_path.parent).parent.parts)}.{test_file.stem}"
|
|
module = importlib.import_module(module_name)
|
|
_file_modules.append(module)
|
|
return _file_modules
|
|
|
|
def get_files(self, apps: list) -> list:
|
|
files = []
|
|
for app in apps:
|
|
app_path = Path(frappe.get_app_path(app))
|
|
for test_file in app_path.glob("**/test_*.py"):
|
|
files.append((app_path, test_file))
|
|
return files
|
|
|
|
def discover_tests(self, params: TestParameters) -> unittest.TestSuite:
|
|
self.params = params
|
|
self.testsuite = unittest.TestSuite()
|
|
|
|
if self.params.tests:
|
|
# handle --test; highest priority; will ignore --doctype and --app
|
|
files = self.get_files(frappe.get_installed_apps())
|
|
file_pymodules = self.load_pymodule_for_files(files)
|
|
self.load_testsuites_in_pymodule(file_pymodules)
|
|
|
|
elif self.params.doctype:
|
|
# handle --doctype; will ignore --app
|
|
module = frappe.get_cached_value("DocType", self.params.doctype, "module")
|
|
app = frappe.get_cached_value("Module Def", module, "app_name")
|
|
pymodule_name = get_module_name(self.params.doctype, module, "test_", app=app)
|
|
pymodule = importlib.import_module(pymodule_name)
|
|
self.load_testsuites_in_pymodule([pymodule])
|
|
|
|
elif self.params.app:
|
|
# handle --app
|
|
files = self.get_files([self.params.app])
|
|
file_pymodules = self.load_pymodule_for_files(files)
|
|
self.load_testsuites_in_pymodule(file_pymodules)
|
|
|
|
elif self.params.module:
|
|
# handle --module; supports --test as well
|
|
pymodule = importlib.import_module(self.params.module)
|
|
self.load_testsuites_in_pymodule([pymodule])
|
|
|
|
return self.testsuite
|