From 713007f035b77d2724f4a471b97f53db1a9a12e3 Mon Sep 17 00:00:00 2001 From: Eleanor Boyd Date: Wed, 19 Jul 2023 14:45:18 -0700 Subject: [PATCH] correct discovery on unittest skip at file level (#21665) given a file called skip_test_file_node.py that has `raise SkipTest(".....")` this should appear in the sidebar with no children. The bug is that currently it shows a "unittest" node that gives "loader" and other incorrect nodes below it. --- .../.data/unittest_skip/unittest_skip_file.py | 10 +++ .../unittest_skip/unittest_skip_function.py | 18 +++++ .../expected_discovery_test_output.py | 68 +++++++++++++++++++ .../tests/unittestadapter/test_discovery.py | 21 +++++- pythonFiles/unittestadapter/utils.py | 8 +++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py create mode 100644 pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py create mode 100644 pythonFiles/tests/unittestadapter/expected_discovery_test_output.py diff --git a/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py new file mode 100644 index 000000000000..927a56bc920b --- /dev/null +++ b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py @@ -0,0 +1,10 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from unittest import SkipTest + +raise SkipTest("This is unittest.SkipTest calling") + + +def test_example(): + assert 1 == 1 diff --git a/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py new file mode 100644 index 000000000000..59e66e9a1d40 --- /dev/null +++ b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py @@ -0,0 +1,18 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import unittest + + +def add(x, y): + return x + y + + +class SimpleTest(unittest.TestCase): + @unittest.skip("demonstrating skipping") + def testadd1(self): + self.assertEquals(add(4, 5), 9) + + +if __name__ == "__main__": + unittest.main() diff --git a/pythonFiles/tests/unittestadapter/expected_discovery_test_output.py b/pythonFiles/tests/unittestadapter/expected_discovery_test_output.py new file mode 100644 index 000000000000..3043ec158a2e --- /dev/null +++ b/pythonFiles/tests/unittestadapter/expected_discovery_test_output.py @@ -0,0 +1,68 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import os +from unittestadapter.utils import TestNodeTypeEnum +from .helpers import TEST_DATA_PATH + +skip_unittest_folder_discovery_output = { + "path": os.fspath(TEST_DATA_PATH / "unittest_skip"), + "name": "unittest_skip", + "type_": TestNodeTypeEnum.folder, + "children": [ + { + "path": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_file.py" + ), + "name": "unittest_skip_file.py", + "type_": TestNodeTypeEnum.file, + "children": [], + "id_": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_file.py" + ), + }, + { + "path": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ), + "name": "unittest_skip_function.py", + "type_": TestNodeTypeEnum.file, + "children": [ + { + "path": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ), + "name": "SimpleTest", + "type_": TestNodeTypeEnum.class_, + "children": [ + { + "name": "testadd1", + "path": os.fspath( + TEST_DATA_PATH + / "unittest_skip" + / "unittest_skip_function.py" + ), + "lineno": "13", + "type_": TestNodeTypeEnum.test, + "id_": os.fspath( + TEST_DATA_PATH + / "unittest_skip" + / "unittest_skip_function.py" + ) + + "\\SimpleTest\\testadd1", + "runID": "unittest_skip_function.SimpleTest.testadd1", + } + ], + "id_": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ) + + "\\SimpleTest", + } + ], + "id_": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ), + }, + ], + "id_": os.fspath(TEST_DATA_PATH / "unittest_skip"), +} diff --git a/pythonFiles/tests/unittestadapter/test_discovery.py b/pythonFiles/tests/unittestadapter/test_discovery.py index 28dc51f55dcd..c4778aa85852 100644 --- a/pythonFiles/tests/unittestadapter/test_discovery.py +++ b/pythonFiles/tests/unittestadapter/test_discovery.py @@ -12,7 +12,7 @@ parse_discovery_cli_args, ) from unittestadapter.utils import TestNodeTypeEnum, parse_unittest_args - +from . import expected_discovery_test_output from .helpers import TEST_DATA_PATH, is_same_tree @@ -214,3 +214,22 @@ def test_error_discovery() -> None: assert actual["status"] == "error" assert is_same_tree(expected, actual.get("tests")) assert len(actual.get("error", [])) == 1 + + +def test_unit_skip() -> None: + """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and test tree. + if unittest discovery was performed and found a test in one file marked as skipped and another file marked as skipped. + """ + start_dir = os.fsdecode(TEST_DATA_PATH / "unittest_skip") + pattern = "unittest_*" + + uuid = "some-uuid" + actual = discover_tests(start_dir, pattern, None, uuid) + + assert actual["status"] == "success" + assert "tests" in actual + assert is_same_tree( + actual.get("tests"), + expected_discovery_test_output.skip_unittest_folder_discovery_output, + ) + assert "error" not in actual diff --git a/pythonFiles/unittestadapter/utils.py b/pythonFiles/unittestadapter/utils.py index a461baf7d870..78000e2a945f 100644 --- a/pythonFiles/unittestadapter/utils.py +++ b/pythonFiles/unittestadapter/utils.py @@ -159,6 +159,14 @@ def build_test_tree( test_id = test_case.id() if test_id.startswith("unittest.loader._FailedTest"): error.append(str(test_case._exception)) # type: ignore + elif test_id.startswith("unittest.loader.ModuleSkipped"): + components = test_id.split(".") + class_name = f"{components[-1]}.py" + # Find/build class node. + file_path = os.fsdecode(os.path.join(directory_path, class_name)) + current_node = get_child_node( + class_name, file_path, TestNodeTypeEnum.file, root + ) else: # Get the static test path components: filename, class name and function name. components = test_id.split(".")