PY-23856: Support tests with docstring and spaces in target

* Targets are trimmed
* When unittest reports test with docstring it should be part of name, but not location
This commit is contained in:
Ilya.Kazakevich
2017-04-21 19:09:40 +03:00
parent 66cce38e53
commit 56e741a29a
8 changed files with 164 additions and 35 deletions
+14 -3
View File
@@ -20,9 +20,13 @@ def _parse_parametrized(part):
Support nose generators / py.test parameters and other functions that provides names like foo(1,2)
Until https://github.com/JetBrains/teamcity-messages/issues/121, all such tests are provided
with parentheses
with parentheses.
Tests with docstring are reported in similar way but they have space before parenthesis and should be ignored
by this function
"""
match = re.match("^(.+)(\\(.+\\))$", part)
match = re.match("^([^\s)(]+)(\\(.+\\))$", part)
if not match:
return [part]
else:
@@ -164,7 +168,14 @@ class NewTeamcityServiceMessages(_old_service_messages):
try:
# Report directory so Java site knows which folder to resolve names against
properties["locationHint"] = "python<{0}>://{1}".format(os.getcwd(), properties["name"])
# tests with docstrings are reported in format "test.name (some test here)".
# text should be part of name, but not location.
possible_location = str(properties["name"])
loc = possible_location.find("(")
if loc > 0:
possible_location = possible_location[:loc].strip()
properties["locationHint"] = "python<{0}>://{1}".format(os.getcwd(), possible_location)
except KeyError:
# If message does not have name, then it is not test
# Simply pass it
@@ -239,7 +239,7 @@ data class ConfigurationTarget(@ConfigField var target: String, @ConfigField var
when (targetType) {
TestTargetType.CUSTOM -> emptyList()
TestTargetType.PYTHON -> getArgumentsForPythonTarget(configuration)
TestTargetType.PATH -> listOf("--path", target)
TestTargetType.PATH -> listOf("--path", target.trim())
}
private fun getArgumentsForPythonTarget(configuration: PyUniversalTestConfiguration): List<String> {
@@ -258,7 +258,7 @@ data class ConfigurationTarget(@ConfigField var target: String, @ConfigField var
folderToStart = LocalFileSystem.getInstance().findFileByPath(configuration.workingDirectorySafe),
allowInaccurateResult = true
)
val qualifiedNameParts = QualifiedName.fromDottedString(target).tryResolveAndSplit(qNameResolveContext) ?:
val qualifiedNameParts = QualifiedName.fromDottedString(target.trim()).tryResolveAndSplit(qNameResolveContext) ?:
throw ExecutionException("Can't find file where $target declared. " +
"Make sure it is in project root")
@@ -0,0 +1,6 @@
def test_evens():
for i in range(0, 5):
yield check_even, i, i*3
def check_even(n, nn):
assert n % 2 == 0 or nn % 2 == 0
@@ -0,0 +1,8 @@
import pytest
@pytest.mark.parametrize("test_input,expected", [
("three plus file", 8),
("(2)+(4)", 6),
(" six times nine.", 42),
])
def test_eval(test_input, expected):
assert eval(test_input) == expected
@@ -0,0 +1,10 @@
from unittest import TestCase
class SomeTestCase(TestCase):
def testSomething(self):
""" Only with docstring test is parsed with extra space"""
self.assertEqual(1 + 1, 2)
def testSomethingBad(self):
"""Fail"""
self.assertEqual(1 + 1, 3)
@@ -6,7 +6,6 @@ import com.jetbrains.env.PyEnvTestCase;
import com.jetbrains.env.PyProcessWithConsoleTestTask;
import com.jetbrains.env.python.testing.CreateConfigurationTestTask.PyConfigurationCreationTask;
import com.jetbrains.env.ut.PyNoseTestProcessRunner;
import com.jetbrains.env.ut.PyUnitTestProcessRunner;
import com.jetbrains.python.sdkTools.SdkCreationType;
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
import com.jetbrains.python.testing.universalTests.PyUniversalNoseTestConfiguration;
@@ -25,6 +24,34 @@ import static org.junit.Assert.assertEquals;
@EnvTestTagsRequired(tags = "nose")
public final class PythonNoseTestingTest extends PyEnvTestCase {
@Test
public void testNoseGenerators() {
runPythonTest(new PyProcessWithConsoleTestTask<PyNoseTestProcessRunner>("/testRunner/env/nose/generators", SdkCreationType.EMPTY_SDK) {
@NotNull
@Override
protected PyNoseTestProcessRunner createProcessRunner() throws Exception {
return new PyNoseTestProcessRunner(toFullPath("test_nose_generator.py"), 1);
}
@Override
protected void checkTestResults(@NotNull final PyNoseTestProcessRunner runner,
@NotNull final String stdout,
@NotNull final String stderr,
@NotNull final String all) {
Assert.assertEquals("Nose genenerator produced bad tree", "Test tree:\n" +
"[root]\n" +
".test_nose_generator\n" +
"..test_evens\n" +
"...(0, 0)(+)\n" +
"...(1, 3)(-)\n" +
"...(2, 6)(+)\n" +
"...(3, 9)(-)\n" +
"...(4, 12)(+)\n", runner.getFormattedTestTree());
}
});
}
// Ensures setup/teardown does not break anything
@Test
public void testSetupTearDown() throws Exception {
@@ -77,6 +77,35 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
}
@Test
public void testParametrized() throws Exception {
runPythonTest(
new PyProcessWithConsoleTestTask<PyTestTestProcessRunner>("/testRunner/env/pytest/parametrized", SdkCreationType.EMPTY_SDK) {
@NotNull
@Override
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
return new PyTestTestProcessRunner("test_pytest_parametrized.py", 1);
}
@Override
protected void checkTestResults(@NotNull final PyTestTestProcessRunner runner,
@NotNull final String stdout,
@NotNull final String stderr,
@NotNull final String all) {
Assert.assertEquals("Parametrized test produced bad tree",
"Test tree:\n" +
"[root]\n" +
".test_pytest_parametrized\n" +
"..test_eval\n" +
"...(three plus file-8)(-)\n" +
"...((2)+(4)-6)(+)\n" +
"...( six times nine_-42)(-)\n", runner.getFormattedTestTree());
}
});
}
// Ensure test survives patched strftime
@Test
public void testMonkeyPatch() throws Exception {
@@ -52,6 +52,45 @@ import static org.junit.Assert.assertEquals;
public final class PythonUnitTestingTest extends PyEnvTestCase {
/**
* tests with docstrings are reported as "test.name (text)" by unittest.
*/
@Test
public void testWithDocString() throws Exception {
runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/withDocString", "test_test.py") {
@NotNull
@Override
protected PyUnitTestProcessRunner createProcessRunner() throws Exception {
return new PyUnitTestProcessRunner(toFullPath(myScriptName), 1);
}
@Override
protected void checkTestResults(@NotNull final PyUnitTestProcessRunner runner,
@NotNull final String stdout,
@NotNull final String stderr,
@NotNull final String all) {
if (runner.getCurrentRerunStep() == 0) {
assertEquals("test with docstring produced bad tree", "Test tree:\n" +
"[root]\n" +
".test_test\n" +
"..SomeTestCase\n" +
"...testSomething (Only with docstring test is parsed with extra space)(+)\n" +
"...testSomethingBad (Fail)(-)\n", runner.getFormattedTestTree());
}
else {
assertEquals("test with docstring failed to rerun",
"Test tree:\n" +
"[root]\n" +
".test_test\n" +
"..SomeTestCase\n" +
"...testSomethingBad (Fail)(-)\n", runner.getFormattedTestTree());
}
}
});
}
/**
* subtest names may have dots and shall not break test tree
*/
@@ -71,22 +110,21 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@NotNull final String stdout,
@NotNull final String stderr,
@NotNull final String all) {
runner.getFormattedTestTree();
assertEquals("dots in subtest names broke output", "Test tree:\n" +
"[root]\n" +
".test_test\n" +
"..SampleTest\n" +
"...test_sample\n" +
"....(i='0_0')(-)\n" +
"....(i='1_1')(-)\n" +
"....(i='2_2')(+)\n" +
"....(i='3_3')(+)\n" +
"....(i='4_4')(+)\n" +
"....(i='5_5')(+)\n" +
"....(i='6_6')(+)\n" +
"....(i='7_7')(+)\n" +
"....(i='8_8')(+)\n" +
"....(i='9_9')(+)\n", runner.getFormattedTestTree());
"[root]\n" +
".test_test\n" +
"..SampleTest\n" +
"...test_sample\n" +
"....(i='0_0')(-)\n" +
"....(i='1_1')(-)\n" +
"....(i='2_2')(+)\n" +
"....(i='3_3')(+)\n" +
"....(i='4_4')(+)\n" +
"....(i='5_5')(+)\n" +
"....(i='6_6')(+)\n" +
"....(i='7_7')(+)\n" +
"....(i='8_8')(+)\n" +
"....(i='9_9')(+)\n", runner.getFormattedTestTree());
}
});
}
@@ -109,20 +147,20 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@NotNull final String all) {
runner.getFormattedTestTree();
assertEquals("unittest2 produced wrong tree", "Test tree:\n" +
"[root]\n" +
".test_test\n" +
"..SampleTest\n" +
"...test_sample\n" +
"....(i=0)(-)\n" +
"....(i=1)(-)\n" +
"....(i=2)(-)\n" +
"....(i=3)(-)\n" +
"....(i=4)(+)\n" +
"....(i=5)(+)\n" +
"....(i=6)(+)\n" +
"....(i=7)(+)\n" +
"....(i=8)(+)\n" +
"....(i=9)(+)\n", runner.getFormattedTestTree());
"[root]\n" +
".test_test\n" +
"..SampleTest\n" +
"...test_sample\n" +
"....(i=0)(-)\n" +
"....(i=1)(-)\n" +
"....(i=2)(-)\n" +
"....(i=3)(-)\n" +
"....(i=4)(+)\n" +
"....(i=5)(+)\n" +
"....(i=6)(+)\n" +
"....(i=7)(+)\n" +
"....(i=8)(+)\n" +
"....(i=9)(+)\n", runner.getFormattedTestTree());
}
});
}