mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-31836: Use pytest parameter as test name, not keyword.
The correct way to use parameters is to add them to the test name. "-k" is also works in some cases, but it is not official nor stable. * pytest runner reports "testname[param]" as metainfo * we fetch param * add "parameters" field to the pytest * glue it with test name GitOrigin-RevId: 56c5d93fd93a12ba5742b21af51ea04823a9d8f7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b88d342c46
commit
4508e0de9d
@@ -213,9 +213,8 @@ class EchoTeamCityMessages(object):
|
||||
|
||||
def pytest_runtest_logstart(self, nodeid, location):
|
||||
# test name fetched from location passed as metainfo to PyCharm
|
||||
# it will be used to run specific test using "-k"
|
||||
# See IDEA-176950
|
||||
# We only need method/function name because only it could be used as -k
|
||||
# it will be used to run specific test
|
||||
# See IDEA-176950, PY-31836
|
||||
test_name = location[2]
|
||||
if test_name:
|
||||
test_name = str(test_name).split(".")[-1]
|
||||
|
||||
@@ -27,15 +27,22 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.jetbrains.python.PyNames
|
||||
import com.jetbrains.python.PythonHelper
|
||||
import com.jetbrains.python.run.targetBasedConfiguration.PyRunTargetVariant
|
||||
import com.jetbrains.python.testing.PyTestSharedForm.*
|
||||
|
||||
/**
|
||||
* Pytest runner
|
||||
*/
|
||||
|
||||
//Fetch param from parametrized test name spam[eggs]
|
||||
private val PARAM_REGEX = Regex("\\[(.+)]$")
|
||||
|
||||
class PyTestSettingsEditor(configuration: PyAbstractTestConfiguration) :
|
||||
PyAbstractTestSettingsEditor(
|
||||
PyTestSharedForm.create(configuration, PyTestSharedForm.CustomOption(
|
||||
PyTestConfiguration::keywords.name, PyRunTargetVariant.PATH, PyRunTargetVariant.PYTHON)))
|
||||
create(
|
||||
configuration,
|
||||
CustomOption(PyTestConfiguration::keywords.name, PyRunTargetVariant.PATH, PyRunTargetVariant.PYTHON),
|
||||
CustomOption(PyTestConfiguration::parameters.name, PyRunTargetVariant.PATH, PyRunTargetVariant.PYTHON)
|
||||
))
|
||||
|
||||
class PyPyTestExecutionEnvironment(configuration: PyTestConfiguration, environment: ExecutionEnvironment) :
|
||||
PyTestExecutionEnvironment<PyTestConfiguration>(configuration, environment) {
|
||||
@@ -52,6 +59,8 @@ class PyTestConfiguration(project: Project, factory: PyTestFactory)
|
||||
: PyAbstractTestConfiguration(project, factory, PyTestFrameworkService.getSdkReadableNameByFramework(PyNames.PY_TEST)) {
|
||||
@ConfigField
|
||||
var keywords: String = ""
|
||||
@ConfigField
|
||||
var parameters: String = ""
|
||||
|
||||
override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? =
|
||||
PyPyTestExecutionEnvironment(this, environment)
|
||||
@@ -70,14 +79,31 @@ class PyTestConfiguration(project: Project, factory: PyTestFactory)
|
||||
return target.generateArgumentsLine(this) + listOf(rawArgumentsSeparator, "--last-failed")
|
||||
}
|
||||
|
||||
override fun getTestSpec(): List<String> {
|
||||
// Parametrized test must add parameter to target.
|
||||
// So, foo.spam becomes foo.spam[param]
|
||||
if (parameters.isNotEmpty() && target.targetType == PyRunTargetVariant.PYTHON) {
|
||||
return super.getTestSpec().toMutableList().apply {
|
||||
this[size - 1] = last() + "[$parameters]"
|
||||
}
|
||||
}
|
||||
return super.getTestSpec()
|
||||
}
|
||||
|
||||
override fun isFrameworkInstalled(): Boolean = VFSTestFrameworkListener.getInstance().isTestFrameworkInstalled(sdk, PyNames.PY_TEST)
|
||||
|
||||
override fun setMetaInfo(metaInfo: String) {
|
||||
keywords = metaInfo
|
||||
// Metainfo contains test name along with params.
|
||||
parameters = getParamFromMetaInfo(metaInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch params from test name
|
||||
*/
|
||||
private fun getParamFromMetaInfo(metaInfo: String) = PARAM_REGEX.find(metaInfo)?.groupValues?.getOrNull(1) ?: ""
|
||||
|
||||
override fun isSameAsLocation(target: ConfigurationTarget, metainfo: String?): Boolean {
|
||||
return super.isSameAsLocation(target, metainfo) && metainfo == keywords
|
||||
return super.isSameAsLocation(target, metainfo) && getParamFromMetaInfo(metainfo ?: "") == parameters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,10 +63,10 @@ import java.util.regex.Matcher
|
||||
* New configuration factories
|
||||
*/
|
||||
internal val pythonFactories get() = arrayOf<PythonConfigurationFactoryBase>(
|
||||
PyUnitTestFactory(),
|
||||
PyTestFactory(),
|
||||
PyNoseTestFactory(),
|
||||
PyTrialTestFactory())
|
||||
PyUnitTestFactory(),
|
||||
PyTestFactory(),
|
||||
PyNoseTestFactory(),
|
||||
PyTrialTestFactory())
|
||||
|
||||
/**
|
||||
* Accepts text that may be wrapped in TC message. Unwraps it and removes TC escape code.
|
||||
@@ -110,7 +110,7 @@ fun isTestElement(element: PsiElement, testCaseClassRequired: ThreeState, typeEv
|
||||
/**
|
||||
* Since runners report names of tests as qualified name, no need to convert it to PSI and back to string.
|
||||
* We just save its name and provide it again to rerun
|
||||
* @param metainfo additional info provided by test runner, in case of pytest it is test name that could be used as "-k" argument
|
||||
* @param metainfo additional info provided by test runner, in case of pytest it is test name with parameters (if test is parametrized)
|
||||
*/
|
||||
private class PyTargetBasedPsiLocation(val target: ConfigurationTarget,
|
||||
element: PsiElement,
|
||||
@@ -483,8 +483,8 @@ abstract class PyAbstractTestConfiguration(project: Project,
|
||||
return ConfigurationTarget(qualifiedName, PyRunTargetVariant.PYTHON).generateArgumentsLine(this)
|
||||
}
|
||||
|
||||
override fun getTestSpec(location: Location<*>,
|
||||
failedTest: AbstractTestProxy): String? {
|
||||
final override fun getTestSpec(location: Location<*>,
|
||||
failedTest: AbstractTestProxy): String? {
|
||||
val list = getPythonTestSpecByLocation(location)
|
||||
if (list.isEmpty()) {
|
||||
return null
|
||||
@@ -504,7 +504,7 @@ abstract class PyAbstractTestConfiguration(project: Project,
|
||||
return result + generateRawArguments(true)
|
||||
}
|
||||
|
||||
fun getTestSpec(): List<String> {
|
||||
open fun getTestSpec(): List<String> {
|
||||
return target.generateArgumentsLine(this) + generateRawArguments()
|
||||
}
|
||||
|
||||
@@ -613,7 +613,8 @@ abstract class PyAbstractTestConfiguration(project: Project,
|
||||
internal open fun shouldSeparateTargetPath(): Boolean = true
|
||||
|
||||
/**
|
||||
* @param metaInfo String "metainfo" field provided by test runner
|
||||
* @param metaInfo String "metainfo" field provided by test runner.
|
||||
* Pytest reports test name with parameters here
|
||||
*/
|
||||
open fun setMetaInfo(metaInfo: String) {
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test name must be reported as meta info to be used as argument for "-k" for parametrized tests
|
||||
* Test name must be reported as meta info to be used as parameter for for parametrized tests
|
||||
*/
|
||||
@Test
|
||||
public void testMetaInfoForMethod() {
|
||||
@@ -234,6 +234,44 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that testName[param] is only launched for parametrized test if param provided
|
||||
*/
|
||||
@Test
|
||||
public void testParametrizedRunByParameter() {
|
||||
runPythonTest(
|
||||
new PyProcessWithConsoleTestTask<PyTestTestProcessRunner>("/testRunner/env/pytest/parametrized", SdkCreationType.EMPTY_SDK) {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PyTestTestProcessRunner createProcessRunner() {
|
||||
return new PyTestTestProcessRunner("test_pytest_parametrized.py", 1) {
|
||||
@Override
|
||||
protected void configurationCreatedAndWillLaunch(@NotNull PyTestConfiguration configuration) throws IOException {
|
||||
super.configurationCreatedAndWillLaunch(configuration);
|
||||
configuration.getTarget().setTarget("test_pytest_parametrized.test_eval");
|
||||
configuration.getTarget().setTargetType(PyRunTargetVariant.PYTHON);
|
||||
configuration.setMetaInfo("test_eval[three plus file-8]");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkTestResults(@NotNull final PyTestTestProcessRunner runner,
|
||||
@NotNull final String stdout,
|
||||
@NotNull final String stderr,
|
||||
@NotNull final String all, int exitCode) {
|
||||
assertEquals("Only one test should be launched",
|
||||
"Test tree:\n" +
|
||||
"[root](-)\n" +
|
||||
".test_pytest_parametrized(-)\n" +
|
||||
"..test_eval(-)\n" +
|
||||
"...(three plus file-8)(-)\n",
|
||||
runner.getFormattedTestTree());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See https://github.com/JetBrains/teamcity-messages/issues/131
|
||||
@@ -497,8 +535,8 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
configuration.setWorkingDirectory(myFixture.getTempDirPath());
|
||||
|
||||
ReadAction.run(() -> Assert.assertThat("Failed to resolve qname",
|
||||
configuration.getTarget().asPsiElement(configuration),
|
||||
Matchers.instanceOf(PyFile.class)));
|
||||
configuration.getTarget().asPsiElement(configuration),
|
||||
Matchers.instanceOf(PyFile.class)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user