diff --git a/python/helpers/pycharm/teamcity/unittestpy.py b/python/helpers/pycharm/teamcity/unittestpy.py index 6f5c14d8f98d..b593873eaca3 100644 --- a/python/helpers/pycharm/teamcity/unittestpy.py +++ b/python/helpers/pycharm/teamcity/unittestpy.py @@ -10,6 +10,7 @@ from teamcity.common import is_string, get_class_fullname, convert_error_to_stri _real_stdout = sys.stdout _real_stderr = sys.stderr +_ERROR_HOLDERS_FQN = ("unittest.suite._ErrorHolder", "unittest2.suite._ErrorHolder") class TeamcityTestResult(TestResult): @@ -33,14 +34,21 @@ class TeamcityTestResult(TestResult): if is_string(test): return test + test_class_fullname = get_class_fullname(test) + test_id = test.id() + + if test_class_fullname in _ERROR_HOLDERS_FQN: + # patch setUpModule (__main__) -> __main__.setUpModule + return re.sub(r'^(.*) \((.*)\)$', r'\2.\1', test_id) + # Force test_id for doctests - if get_class_fullname(test) != "doctest.DocTestCase": + if test_class_fullname != "doctest.DocTestCase": desc = test.shortDescription() test_method_name = getattr(test, "_testMethodName", "") - if desc and desc != test.id() and desc != test_method_name: - return "%s (%s)" % (test.id(), desc.replace('.', '_')) + if desc and desc != test_id and desc != test_method_name: + return "%s (%s)" % (test_id, desc.replace('.', '_')) - return test.id() + return test_id def addSuccess(self, test): super(TeamcityTestResult, self).addSuccess(test) @@ -92,7 +100,14 @@ class TeamcityTestResult(TestResult): self.messages.blockClosed(block_id, flowId=parent_test_id) else: test_id = self.get_test_id(test) - self.messages.testIgnored(test_id, message="Skipped" + reason_str, flowId=test_id) + + if test_id not in self.test_started_datetime_map: + # Test ignored without startTest. Handle start and finish events ourselves + self.messages.testStarted(test_id, flowId=test_id) + self.messages.testIgnored(test_id, message="Skipped" + reason_str, flowId=test_id) + self.messages.testFinished(test_id, flowId=test_id) + else: + self.messages.testIgnored(test_id, message="Skipped" + reason_str, flowId=test_id) def addUnexpectedSuccess(self, test): _super = super(TeamcityTestResult, self) @@ -108,17 +123,13 @@ class TeamcityTestResult(TestResult): super(TeamcityTestResult, self).addError(test, err) test_class = get_class_fullname(test) - if test_class == "unittest.suite._ErrorHolder" or test_class == "unittest2.suite._ErrorHolder": + if test_class in _ERROR_HOLDERS_FQN: # This is a standalone error + test_id = self.get_test_id(test) - test_name = test.id() - # patch setUpModule (__main__) -> __main__.setUpModule - test_name = re.sub(r'^(.*) \((.*)\)$', r'\2.\1', test_name) - - self.messages.testStarted(test_name, flowId=test_name) - # noinspection PyTypeChecker - self.report_fail(test_name, 'Failure', err) - self.messages.testFinished(test_name, flowId=test_name) + self.messages.testStarted(test_id, flowId=test_id) + self.report_fail(test, 'Failure', err) + self.messages.testFinished(test_id, flowId=test_id) elif get_class_fullname(err[0]) == "unittest2.case.SkipTest": message = "" if hasattr(err[1], "message"): diff --git a/python/testData/testRunner/env/unit/skipInSetup/test_test.py b/python/testData/testRunner/env/unit/skipInSetup/test_test.py new file mode 100644 index 000000000000..15a8fa60d43a --- /dev/null +++ b/python/testData/testRunner/env/unit/skipInSetup/test_test.py @@ -0,0 +1,23 @@ +import unittest + + +class TestSimple(unittest.TestCase): + + @classmethod + def setUpClass(cls): + raise unittest.SkipTest("Skip whole Case") + + def test_true(self): + self.assertTrue(True) + + def test_false(self): + self.assertTrue(False, msg="Is not True") + + def test_skip(self): + raise unittest.SkipTest("Skip this test") + + +class TestSubSimple(TestSimple): + + def test_subclass(self): + self.assertTrue(True) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java index d9b540db95cb..f24a164b95b2 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java +++ b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java @@ -271,6 +271,31 @@ public final class PythonUnitTestingTest extends PyEnvTestCase { } + /** + * Raising SkipTest on class setup should not lead to KeyError + */ + @Test + public void testSkipInSetup() throws Exception { + runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/skipInSetup", "test_test.py") { + + + @Override + protected void checkTestResults(@NotNull final PyUnitTestProcessRunner runner, + @NotNull final String stdout, + @NotNull final String stderr, + @NotNull final String all) { + Assert.assertEquals("Output tree broken for skipped exception thrown in setup method" ,"Test tree:\n" + + "[root]\n" + + ".test_test\n" + + "..TestSimple\n" + + "...setUpClass(~)\n" + + "..TestSubSimple\n" + + "...setUpClass(~)\n", runner.getFormattedTestTree()); + } + }); + } + + /** * Ensure that sys.path[0] is script folder, not helpers folder */