Merge branch 'main' into verify-setup
This commit is contained in:
commit
31b586b5d0
2 changed files with 334 additions and 35 deletions
|
|
@ -180,46 +180,56 @@ def process_test_files(
|
|||
for test_file, functions in file_to_test_map.items():
|
||||
script = jedi.Script(path=test_file, project=jedi_project)
|
||||
test_functions = set()
|
||||
top_level_names = script.get_names()
|
||||
|
||||
all_names = script.get_names(all_scopes=True, references=True)
|
||||
all_defs = script.get_names(all_scopes=True, definitions=True)
|
||||
all_names_top = script.get_names(all_scopes=True)
|
||||
|
||||
for name in top_level_names:
|
||||
if test_framework == "pytest":
|
||||
functions_to_search = [elem.test_function for elem in functions]
|
||||
for i, function in enumerate(functions_to_search):
|
||||
if "[" in function:
|
||||
function_name = re.split(r"[\[\]]", function)[0]
|
||||
parameters = re.split(r"[\[\]]", function)[1]
|
||||
if name.name == function_name and name.type == "function":
|
||||
test_functions.add(TestFunction(name.name, None, parameters, functions[i].test_type))
|
||||
elif name.name == function and name.type == "function":
|
||||
test_functions.add(TestFunction(name.name, None, None, functions[i].test_type))
|
||||
break
|
||||
if test_framework == "unittest":
|
||||
functions_to_search = [elem.test_function for elem in functions]
|
||||
test_suites = [elem.test_suite for elem in functions]
|
||||
top_level_functions = {name.name: name for name in all_names_top if name.type == "function"}
|
||||
top_level_classes = {name.name: name for name in all_names_top if name.type == "class"}
|
||||
|
||||
if name.name in test_suites and name.type == "class":
|
||||
for def_name in all_defs:
|
||||
if (
|
||||
def_name.type == "function"
|
||||
and def_name.full_name is not None
|
||||
and f".{name.name}." in def_name.full_name
|
||||
):
|
||||
for function in functions_to_search:
|
||||
(is_parameterized, new_function, parameters) = discover_parameters_unittest(function)
|
||||
if test_framework == "pytest":
|
||||
functions_to_search = [elem.test_function for elem in functions]
|
||||
for i, function in enumerate(functions_to_search):
|
||||
if "[" in function:
|
||||
function_name = re.split(r"[\[\]]", function)[0]
|
||||
parameters = re.split(r"[\[\]]", function)[1]
|
||||
if function_name in top_level_functions:
|
||||
test_functions.add(TestFunction(function_name, None, parameters, functions[i].test_type))
|
||||
elif function in top_level_functions:
|
||||
test_functions.add(TestFunction(function, None, None, functions[i].test_type))
|
||||
elif re.match(r"^test_\w+_\d+(?:_\w+)*", function):
|
||||
# Try to match parameterized unittest functions here, although we can't get the parameters.
|
||||
# Extract base name by removing the numbered suffix and any additional descriptions
|
||||
base_name = re.sub(r"_\d+(?:_\w+)*$", "", function)
|
||||
if base_name in top_level_functions:
|
||||
test_functions.add(TestFunction(base_name, None, function, functions[i].test_type))
|
||||
|
||||
if is_parameterized and new_function == def_name.name:
|
||||
test_functions.add(
|
||||
TestFunction(
|
||||
def_name.name, name.name, parameters, functions[0].test_type
|
||||
) # A test file must not have more than one test type
|
||||
)
|
||||
elif function == def_name.name:
|
||||
test_functions.add(
|
||||
TestFunction(def_name.name, name.name, None, functions[0].test_type)
|
||||
)
|
||||
elif test_framework == "unittest":
|
||||
functions_to_search = [elem.test_function for elem in functions]
|
||||
test_suites = [elem.test_suite for elem in functions]
|
||||
|
||||
matching_names = test_suites & top_level_classes.keys()
|
||||
for matched_name in matching_names:
|
||||
for def_name in all_defs:
|
||||
if (
|
||||
def_name.type == "function"
|
||||
and def_name.full_name is not None
|
||||
and f".{matched_name}." in def_name.full_name
|
||||
):
|
||||
for function in functions_to_search:
|
||||
(is_parameterized, new_function, parameters) = discover_parameters_unittest(function)
|
||||
|
||||
if is_parameterized and new_function == def_name.name:
|
||||
test_functions.add(
|
||||
TestFunction(
|
||||
def_name.name, matched_name, parameters, functions[0].test_type
|
||||
) # A test file must not have more than one test type
|
||||
)
|
||||
elif function == def_name.name:
|
||||
test_functions.add(
|
||||
TestFunction(def_name.name, matched_name, None, functions[0].test_type)
|
||||
)
|
||||
|
||||
test_functions_list = list(test_functions)
|
||||
test_functions_raw = [elem.function_name for elem in test_functions_list]
|
||||
|
|
|
|||
|
|
@ -446,3 +446,292 @@ def test_discover_tests_pytest_separate_moduledir():
|
|||
# Check if the test for the nested class method is discovered
|
||||
assert len(discovered_tests) == 1
|
||||
assert discovered_tests["mypackage.code.find_common_tags"][0].tests_in_file.test_file == test_file_path
|
||||
|
||||
|
||||
def test_unittest_discovery_with_pytest():
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
path_obj_tmpdirname = Path(tmpdirname)
|
||||
|
||||
# Create a simple code file
|
||||
code_file_path = path_obj_tmpdirname / "calculator.py"
|
||||
code_file_content = """
|
||||
class Calculator:
|
||||
def add(self, a, b):
|
||||
return a + b
|
||||
"""
|
||||
code_file_path.write_text(code_file_content)
|
||||
|
||||
# Create a unittest test file
|
||||
test_file_path = path_obj_tmpdirname / "test_calculator.py"
|
||||
test_file_content = """
|
||||
import unittest
|
||||
from calculator import Calculator
|
||||
|
||||
class TestCalculator(unittest.TestCase):
|
||||
def test_add(self):
|
||||
calc = Calculator()
|
||||
self.assertEqual(calc.add(2, 2), 4)
|
||||
"""
|
||||
test_file_path.write_text(test_file_content)
|
||||
|
||||
# Configure test discovery
|
||||
test_config = TestConfig(
|
||||
tests_root=path_obj_tmpdirname,
|
||||
project_root_path=path_obj_tmpdirname,
|
||||
test_framework="pytest", # Using pytest framework to discover unittest tests
|
||||
tests_project_rootdir=path_obj_tmpdirname.parent,
|
||||
)
|
||||
|
||||
# Discover tests
|
||||
discovered_tests = discover_unit_tests(test_config)
|
||||
|
||||
# Verify the unittest was discovered
|
||||
assert len(discovered_tests) == 1
|
||||
assert "calculator.Calculator.add" in discovered_tests
|
||||
assert len(discovered_tests["calculator.Calculator.add"]) == 1
|
||||
assert discovered_tests["calculator.Calculator.add"][0].tests_in_file.test_file == test_file_path
|
||||
assert discovered_tests["calculator.Calculator.add"][0].tests_in_file.test_function == "test_add"
|
||||
|
||||
|
||||
def test_unittest_discovery_with_pytest_parent_class():
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
path_obj_tmpdirname = Path(tmpdirname)
|
||||
|
||||
# Create a simple code file
|
||||
code_file_path = path_obj_tmpdirname / "calculator.py"
|
||||
code_file_content = """
|
||||
class Calculator:
|
||||
def add(self, a, b):
|
||||
return a + b
|
||||
"""
|
||||
code_file_path.write_text(code_file_content)
|
||||
|
||||
# Create a base test class file
|
||||
base_test_file_path = path_obj_tmpdirname / "base_test.py"
|
||||
base_test_content = """
|
||||
import unittest
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.setup_called = True
|
||||
|
||||
def tearDown(self):
|
||||
self.setup_called = False
|
||||
|
||||
def assert_setup_called(self):
|
||||
self.assertTrue(self.setup_called, "Setup was not called")
|
||||
"""
|
||||
base_test_file_path.write_text(base_test_content)
|
||||
|
||||
# Create a unittest test file that extends the base test
|
||||
test_file_path = path_obj_tmpdirname / "test_calculator.py"
|
||||
test_file_content = """
|
||||
from base_test import BaseTestCase
|
||||
from calculator import Calculator
|
||||
|
||||
class ExtendedTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.calc = Calculator()
|
||||
|
||||
class TestCalculator(ExtendedTestCase):
|
||||
def test_add(self):
|
||||
self.assert_setup_called()
|
||||
self.assertEqual(self.calc.add(2, 2), 4)
|
||||
"""
|
||||
test_file_path.write_text(test_file_content)
|
||||
|
||||
# Configure test discovery
|
||||
test_config = TestConfig(
|
||||
tests_root=path_obj_tmpdirname,
|
||||
project_root_path=path_obj_tmpdirname,
|
||||
test_framework="pytest", # Using pytest framework to discover unittest tests
|
||||
tests_project_rootdir=path_obj_tmpdirname.parent,
|
||||
)
|
||||
|
||||
# Discover tests
|
||||
discovered_tests = discover_unit_tests(test_config)
|
||||
|
||||
# Verify the unittest was discovered
|
||||
assert len(discovered_tests) == 2
|
||||
assert "calculator.Calculator.add" in discovered_tests
|
||||
assert len(discovered_tests["calculator.Calculator.add"]) == 1
|
||||
assert discovered_tests["calculator.Calculator.add"][0].tests_in_file.test_file == test_file_path
|
||||
assert discovered_tests["calculator.Calculator.add"][0].tests_in_file.test_function == "test_add"
|
||||
|
||||
|
||||
def test_unittest_discovery_with_pytest_private():
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
path_obj_tmpdirname = Path(tmpdirname)
|
||||
|
||||
# Create a simple code file
|
||||
code_file_path = path_obj_tmpdirname / "calculator.py"
|
||||
code_file_content = """
|
||||
class Calculator:
|
||||
def add(self, a, b):
|
||||
return a + b
|
||||
"""
|
||||
code_file_path.write_text(code_file_content)
|
||||
|
||||
# Create a unittest test file with a private test method (prefixed with _)
|
||||
test_file_path = path_obj_tmpdirname / "test_calculator.py"
|
||||
test_file_content = """
|
||||
import unittest
|
||||
from calculator import Calculator
|
||||
|
||||
class TestCalculator(unittest.TestCase):
|
||||
def _test_add(self): # Private test method should not be discovered
|
||||
calc = Calculator()
|
||||
self.assertEqual(calc.add(2, 2), 4)
|
||||
"""
|
||||
test_file_path.write_text(test_file_content)
|
||||
|
||||
# Configure test discovery
|
||||
test_config = TestConfig(
|
||||
tests_root=path_obj_tmpdirname,
|
||||
project_root_path=path_obj_tmpdirname,
|
||||
test_framework="pytest", # Using pytest framework to discover unittest tests
|
||||
tests_project_rootdir=path_obj_tmpdirname.parent,
|
||||
)
|
||||
|
||||
# Discover tests
|
||||
discovered_tests = discover_unit_tests(test_config)
|
||||
|
||||
# Verify no tests were discovered
|
||||
assert len(discovered_tests) == 0
|
||||
assert "calculator.Calculator.add" not in discovered_tests
|
||||
|
||||
|
||||
def test_unittest_discovery_with_pytest_subtest():
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
path_obj_tmpdirname = Path(tmpdirname)
|
||||
|
||||
# Create a simple code file
|
||||
code_file_path = path_obj_tmpdirname / "calculator.py"
|
||||
code_file_content = """
|
||||
class Calculator:
|
||||
def add(self, a, b):
|
||||
return a + b
|
||||
"""
|
||||
code_file_path.write_text(code_file_content)
|
||||
|
||||
# Create a unittest test file with parameterized tests
|
||||
test_file_path = path_obj_tmpdirname / "test_calculator.py"
|
||||
test_file_content = """
|
||||
import unittest
|
||||
from calculator import Calculator
|
||||
|
||||
class TestCalculator(unittest.TestCase):
|
||||
def test_add_with_parameters(self):
|
||||
calc = Calculator()
|
||||
test_cases = [
|
||||
{"a": 2, "b": 2, "expected": 4},
|
||||
{"a": 0, "b": 0, "expected": 0},
|
||||
{"a": -1, "b": 1, "expected": 0},
|
||||
{"a": 10, "b": -5, "expected": 5}
|
||||
]
|
||||
|
||||
for case in test_cases:
|
||||
with self.subTest(a=case["a"], b=case["b"]):
|
||||
result = calc.add(case["a"], case["b"])
|
||||
self.assertEqual(result, case["expected"])
|
||||
"""
|
||||
test_file_path.write_text(test_file_content)
|
||||
|
||||
# Configure test discovery
|
||||
test_config = TestConfig(
|
||||
tests_root=path_obj_tmpdirname,
|
||||
project_root_path=path_obj_tmpdirname,
|
||||
test_framework="pytest", # Using pytest framework to discover unittest tests
|
||||
tests_project_rootdir=path_obj_tmpdirname.parent,
|
||||
)
|
||||
|
||||
# Discover tests
|
||||
discovered_tests = discover_unit_tests(test_config)
|
||||
|
||||
# Verify the unittest was discovered
|
||||
assert len(discovered_tests) == 1
|
||||
assert "calculator.Calculator.add" in discovered_tests
|
||||
assert len(discovered_tests["calculator.Calculator.add"]) == 1
|
||||
assert discovered_tests["calculator.Calculator.add"][0].tests_in_file.test_file == test_file_path
|
||||
assert (
|
||||
discovered_tests["calculator.Calculator.add"][0].tests_in_file.test_function == "test_add_with_parameters"
|
||||
)
|
||||
|
||||
|
||||
def test_unittest_discovery_with_pytest_parameterized():
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
path_obj_tmpdirname = Path(tmpdirname)
|
||||
|
||||
# Create a simple code file
|
||||
code_file_path = path_obj_tmpdirname / "calculator.py"
|
||||
code_file_content = """
|
||||
class Calculator:
|
||||
def add(self, a, b):
|
||||
return a + b
|
||||
|
||||
def multiply(self, a, b):
|
||||
return a * b
|
||||
"""
|
||||
code_file_path.write_text(code_file_content)
|
||||
|
||||
# Create a unittest test file with different parameterized patterns
|
||||
test_file_path = path_obj_tmpdirname / "test_calculator.py"
|
||||
test_file_content = """
|
||||
import unittest
|
||||
from parameterized import parameterized
|
||||
from calculator import Calculator
|
||||
|
||||
class TestCalculator(unittest.TestCase):
|
||||
# Test with named parameters
|
||||
@parameterized.expand([
|
||||
("positive_numbers", 2, 2, 4),
|
||||
("zeros", 0, 0, 0),
|
||||
("negative_and_positive", -1, 1, 0),
|
||||
("negative_result", 10, -15, -5),
|
||||
])
|
||||
def test_add(self, name, a, b, expected):
|
||||
calc = Calculator()
|
||||
result = calc.add(a, b)
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
# Test with unnamed parameters
|
||||
@parameterized.expand([
|
||||
(2, 3, 6),
|
||||
(0, 5, 0),
|
||||
(-2, 3, -6),
|
||||
])
|
||||
def test_multiply(self, a, b, expected):
|
||||
calc = Calculator()
|
||||
result = calc.multiply(a, b)
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
# Test with mixed naming patterns
|
||||
@parameterized.expand([
|
||||
("test with spaces", 1, 1, 2),
|
||||
("test_with_underscores", 2, 2, 4),
|
||||
("test.with.dots", 3, 3, 6),
|
||||
("test-with-hyphens", 4, 4, 8),
|
||||
])
|
||||
def test_add_mixed(self, name, a, b, expected):
|
||||
calc = Calculator()
|
||||
result = calc.add(a, b)
|
||||
self.assertEqual(result, expected)
|
||||
"""
|
||||
test_file_path.write_text(test_file_content)
|
||||
|
||||
# Configure test discovery
|
||||
test_config = TestConfig(
|
||||
tests_root=path_obj_tmpdirname,
|
||||
project_root_path=path_obj_tmpdirname,
|
||||
test_framework="pytest",
|
||||
tests_project_rootdir=path_obj_tmpdirname.parent,
|
||||
)
|
||||
|
||||
# Discover tests
|
||||
discovered_tests = discover_unit_tests(test_config)
|
||||
|
||||
# Verify the basic structure
|
||||
assert len(discovered_tests) == 2 # Should have tests for both add and multiply
|
||||
assert "calculator.Calculator.add" in discovered_tests
|
||||
assert "calculator.Calculator.multiply" in discovered_tests
|
||||
|
|
|
|||
Loading…
Reference in a new issue