Skip to content

Commit 4ffbdcc

Browse files
karthiknadigeleanorjboyd
authored andcommitted
Fix for unittest with testscenarios (microsoft/vscode-python#23230)
Fixes microsoft/vscode-python#17641 --------- Co-authored-by: eleanorjboyd <[email protected]>
1 parent 6af0e9a commit 4ffbdcc

File tree

5 files changed

+95
-13
lines changed

5 files changed

+95
-13
lines changed

extensions/positron-python/build/test-requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ flask
1212
fastapi
1313
uvicorn
1414
django
15+
testresources
16+
testscenarios
1517

1618
# Integrated TensorBoard tests
1719
tensorboard
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import os
5+
6+
import testresources
7+
from testscenarios import generate_scenarios
8+
9+
def load_tests(loader, tests, pattern):
10+
this_dir = os.path.dirname(__file__)
11+
mytests = loader.discover(start_dir=this_dir, pattern=pattern)
12+
result = testresources.OptimisingTestSuite()
13+
result.addTests(generate_scenarios(mytests))
14+
result.addTests(generate_scenarios(tests))
15+
return result
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from testscenarios import TestWithScenarios
5+
6+
class TestMathOperations(TestWithScenarios):
7+
scenarios = [
8+
('add', {'test_id': 'test_add', 'a': 5, 'b': 3, 'expected': 8}),
9+
('subtract', {'test_id': 'test_subtract', 'a': 5, 'b': 3, 'expected': 2}),
10+
('multiply', {'test_id': 'test_multiply', 'a': 5, 'b': 3, 'expected': 15})
11+
]
12+
a: int = 0
13+
b: int = 0
14+
expected: int = 0
15+
test_id: str = ""
16+
17+
def test_operations(self):
18+
result = None
19+
if self.test_id == 'test_add':
20+
result = self.a + self.b
21+
elif self.test_id == 'test_subtract':
22+
result = self.a - self.b
23+
elif self.test_id == 'test_multiply':
24+
result = self.a * self.b
25+
self.assertEqual(result, self.expected)

extensions/positron-python/python_files/tests/unittestadapter/test_execution.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def test_subtest_run(mock_send_run_data) -> None:
141141
"pattern_a_test.DiscoveryA.test_one_a",
142142
"pattern_a_test.DiscoveryA.test_two_a",
143143
],
144-
"*test",
144+
"*test.py",
145145
os.fspath(TEST_DATA_PATH / "two_patterns"),
146146
"success",
147147
),
@@ -174,6 +174,16 @@ def test_subtest_run(mock_send_run_data) -> None:
174174
os.fspath(TEST_DATA_PATH),
175175
"success",
176176
),
177+
(
178+
[
179+
"test_scene.TestMathOperations.test_operations(add)",
180+
"test_scene.TestMathOperations.test_operations(subtract)",
181+
"test_scene.TestMathOperations.test_operations(multiply)",
182+
],
183+
"*",
184+
os.fspath(TEST_DATA_PATH / "test_scenarios" / "tests"),
185+
"success",
186+
),
177187
],
178188
)
179189
def test_multiple_ids_run(mock_send_run_data, test_ids, pattern, cwd, expected_outcome) -> None:

extensions/positron-python/python_files/unittestadapter/execution.py

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,35 @@ def formatResult(
143143
send_run_data(result, test_run_pipe)
144144

145145

146+
def filter_tests(suite: unittest.TestSuite, test_ids: List[str]) -> unittest.TestSuite:
147+
"""Filter the tests in the suite to only run the ones with the given ids."""
148+
filtered_suite = unittest.TestSuite()
149+
for test in suite:
150+
if isinstance(test, unittest.TestCase):
151+
if test.id() in test_ids:
152+
filtered_suite.addTest(test)
153+
else:
154+
filtered_suite.addTest(filter_tests(test, test_ids))
155+
return filtered_suite
156+
157+
158+
def get_all_test_ids(suite: unittest.TestSuite) -> List[str]:
159+
"""Return a list of all test ids in the suite."""
160+
test_ids = []
161+
for test in suite:
162+
if isinstance(test, unittest.TestCase):
163+
test_ids.append(test.id())
164+
else:
165+
test_ids.extend(get_all_test_ids(test))
166+
return test_ids
167+
168+
169+
def find_missing_tests(test_ids: List[str], suite: unittest.TestSuite) -> List[str]:
170+
"""Return a list of test ids that are not in the suite."""
171+
all_test_ids = get_all_test_ids(suite)
172+
return [test_id for test_id in test_ids if test_id not in all_test_ids]
173+
174+
146175
# Args: start_path path to a directory or a file, list of ids that may be empty.
147176
# Edge cases:
148177
# - if tests got deleted since the VS Code side last ran discovery and the current test run,
@@ -169,16 +198,6 @@ def run_tests(
169198
start_dir = os.path.dirname(cwd)
170199
pattern = os.path.basename(cwd)
171200

172-
# Discover tests at path with the file name as a pattern (if any).
173-
loader = unittest.TestLoader()
174-
175-
args = { # noqa: F841
176-
"start_dir": start_dir,
177-
"pattern": pattern,
178-
"top_level_dir": top_level_dir,
179-
}
180-
suite = loader.discover(start_dir, pattern, top_level_dir) # noqa: F841
181-
182201
if failfast is None:
183202
failfast = False
184203
if locals is None:
@@ -191,9 +210,20 @@ def run_tests(
191210
failfast=failfast,
192211
verbosity=verbosity,
193212
)
194-
# lets try to tailer our own suite so we can figure out running only the ones we want
213+
214+
# Discover tests at path with the file name as a pattern (if any).
195215
loader = unittest.TestLoader()
196-
tailor: unittest.TestSuite = loader.loadTestsFromNames(test_ids)
216+
suite = loader.discover(start_dir, pattern, top_level_dir)
217+
218+
# lets try to tailer our own suite so we can figure out running only the ones we want
219+
tailor: unittest.TestSuite = filter_tests(suite, test_ids)
220+
221+
# If any tests are missing, add them to the payload.
222+
not_found = find_missing_tests(test_ids, tailor)
223+
if not_found:
224+
missing_suite = loader.loadTestsFromNames(not_found)
225+
tailor.addTests(missing_suite)
226+
197227
result: UnittestTestResult = runner.run(tailor) # type: ignore
198228

199229
payload["result"] = result.formatted

0 commit comments

Comments
 (0)