mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-38775: Generate tests even for empty classes.
When user wants to generate test for class ``SpamEggs`` that has no methods: * For pytest generate "test_spam_eggs" function * for UniTest "class TestSpamEggs" ``PyTestCreationModel`` also rewritten a little to make it slightly more readable. GitOrigin-RevId: cc5d774ad684844f5fd9c86634dbcd0d2343437f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d05a117091
commit
b4e6e537b6
+38
-19
@@ -22,37 +22,56 @@ class PyTestCreationModel(var fileName: String,
|
||||
var methods: List<String>) {
|
||||
|
||||
init {
|
||||
assert(methods.isNotEmpty()) { "Provide at least one method" }
|
||||
assert(className.isNotEmpty() || methods.isNotEmpty()) { "Either class or at least one method must be provided" }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val String.asFunName
|
||||
get():String {
|
||||
return replace(Regex("([a-z])([A-Z])"), "$1_$2").toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return model of null if no test could be created for this element
|
||||
*/
|
||||
fun createByElement(element: PsiElement): PyTestCreationModel? {
|
||||
if (PythonUnitTestUtil.isTestElement(element, null)) return null //Can't create tests for tests
|
||||
val file = element.containingFile as? PyFile ?: return null
|
||||
val pyClass = PsiTreeUtil.getParentOfType(element, PyClass::class.java, false)
|
||||
val function = PsiTreeUtil.getParentOfType(element, PyFunction::class.java, false)
|
||||
val elementsToTest: Sequence<PsiNamedElement> = when {
|
||||
function != null -> listOf(function)
|
||||
pyClass != null -> pyClass.methods.asList()
|
||||
else -> (file.topLevelFunctions + file.topLevelClasses) as List<PsiNamedElement>
|
||||
}.asSequence().filterNot { PythonUnitTestUtil.isTestElement(it, null) }
|
||||
val fileUnderTest = element.containingFile as? PyFile ?: return null
|
||||
val classUnderTest = PsiTreeUtil.getParentOfType(element, PyClass::class.java, false)
|
||||
val functionUnderTest = PsiTreeUtil.getParentOfType(element, PyFunction::class.java, false)
|
||||
val elementsUnderTest: Sequence<PsiNamedElement> = when {
|
||||
functionUnderTest != null -> listOf(functionUnderTest)
|
||||
classUnderTest != null -> classUnderTest.methods.asList()
|
||||
else -> (fileUnderTest.topLevelFunctions + fileUnderTest.topLevelClasses)
|
||||
}.asSequence().filterIsInstance<PsiNamedElement>().filterNot { PythonUnitTestUtil.isTestElement(it, null) }
|
||||
|
||||
val functionNames = elementsToTest
|
||||
.filterNot { it.name?.startsWith("__") == true }
|
||||
|
||||
/**
|
||||
* [PyTestCreationModel] has optional field "class" and list of methods.
|
||||
* For unitTest we need "class" field to filled by test name.
|
||||
* For pytest we may leave it empty, but we need at least one method.
|
||||
*/
|
||||
|
||||
val testFunctionNames = elementsUnderTest
|
||||
.mapNotNull { it.name }
|
||||
.map { "test_${it.toLowerCase()}" }.toList()
|
||||
.filterNot { it.startsWith("__") }
|
||||
.map { "test_${it.asFunName}" }.toMutableList()
|
||||
|
||||
return if (functionNames.isEmpty()) null
|
||||
else {
|
||||
val className = if (PythonUnitTestUtil.isTestCaseClassRequired(file)) "Test${pyClass?.name ?: ""}" else ""
|
||||
PyTestCreationModel(fileName = "test_${file.name}",
|
||||
targetDir = getTestFolder(element).path,
|
||||
className = className,
|
||||
methods = functionNames)
|
||||
val nameOfClassUnderTest = classUnderTest?.name
|
||||
// True for unitTest
|
||||
val testCaseClassRequired = PythonUnitTestUtil.isTestCaseClassRequired(fileUnderTest)
|
||||
if (testFunctionNames.isEmpty()) {
|
||||
when {
|
||||
// No class, no function, what to generate?
|
||||
classUnderTest == null -> return null
|
||||
// For UnitTest we can generate test class. For pytest we need at least one function
|
||||
!testCaseClassRequired -> testFunctionNames.add("test_" + (nameOfClassUnderTest?.asFunName ?: "fun"))
|
||||
}
|
||||
}
|
||||
return PyTestCreationModel(fileName = "test_${fileUnderTest.name}",
|
||||
targetDir = getTestFolder(element).path,
|
||||
className = if (testCaseClassRequired) "Test${nameOfClassUnderTest ?: ""}" else "",
|
||||
methods = testFunctionNames)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,3 +9,6 @@ class Spam:
|
||||
|
||||
def test_foo():
|
||||
pass
|
||||
|
||||
class SpamSpamSpamBakedBeans:
|
||||
pass
|
||||
|
||||
+56
-41
@@ -3,15 +3,14 @@ package com.jetbrains.python.codeInsight.testIntegration
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.testFramework.VfsTestUtil
|
||||
import com.jetbrains.python.PyNames
|
||||
import com.jetbrains.python.fixtures.PyTestCase
|
||||
import com.jetbrains.python.psi.PyFile
|
||||
import com.jetbrains.python.testing.PyTestFrameworkService
|
||||
import com.jetbrains.python.testing.PythonTestConfigurationsModel
|
||||
import com.jetbrains.python.testing.TestRunnerService
|
||||
import org.junit.Assert
|
||||
|
||||
class PyTestCreationModelTest : PyTestCase() {
|
||||
private val dir get() = myFixture.file.containingDirectory.virtualFile
|
||||
@@ -19,59 +18,75 @@ class PyTestCreationModelTest : PyTestCase() {
|
||||
private val service: TestRunnerService get() = TestRunnerService.getInstance(myFixture.module)
|
||||
private val testsFolderName = "tests"
|
||||
|
||||
fun testWithUnitTest() {
|
||||
service.projectConfiguration = PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME
|
||||
val modelToTestClass = getModel(true)!!
|
||||
Assert.assertEquals("test_create_tst.py", modelToTestClass.fileName)
|
||||
Assert.assertEquals("TestSpam", modelToTestClass.className)
|
||||
Assert.assertEquals(dirPath, modelToTestClass.targetDir)
|
||||
Assert.assertEquals(modelToTestClass.methods, listOf("test_eggs", "test_eggs_and_ham"))
|
||||
|
||||
val modelToTestFunction = getModel(false)!!
|
||||
Assert.assertEquals("test_create_tst.py", modelToTestFunction.fileName)
|
||||
Assert.assertEquals("Test", modelToTestFunction.className)
|
||||
Assert.assertEquals(dirPath, modelToTestClass.targetDir)
|
||||
Assert.assertEquals(modelToTestFunction.methods, listOf("test_test_foo"))
|
||||
}
|
||||
|
||||
fun testWithPyTest() {
|
||||
service.projectConfiguration = PyTestFrameworkService.getSdkReadableNameByFramework(PyNames.PY_TEST)
|
||||
val modelToTestClass = getModel(true)!!
|
||||
Assert.assertEquals("test_create_tst.py", modelToTestClass.fileName)
|
||||
Assert.assertEquals("", modelToTestClass.className)
|
||||
Assert.assertEquals(dirPath, modelToTestClass.targetDir)
|
||||
Assert.assertEquals(modelToTestClass.methods, listOf("test_eggs", "test_eggs_and_ham"))
|
||||
|
||||
Assert.assertNull("test_foo is test from pytest point of view, can't test it", getModel(false))
|
||||
}
|
||||
|
||||
fun testTestFolderDetected() {
|
||||
ApplicationManager.getApplication().invokeAndWait {
|
||||
WriteAction.runAndWait<Throwable> {
|
||||
VfsUtil.createDirectoryIfMissing(dir, testsFolderName)
|
||||
}
|
||||
}
|
||||
val modelToTestClass = getModel(true)!!
|
||||
Assert.assertEquals(dir.findChild(testsFolderName)!!.path, modelToTestClass.targetDir)
|
||||
}
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
myFixture.configureByFile("/create_tests/create_tst.py")
|
||||
}
|
||||
|
||||
fun testWithUnitTest() {
|
||||
service.projectConfiguration = PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME
|
||||
val modelToTestClass = getModel()!!
|
||||
assertEquals("test_create_tst.py", modelToTestClass.fileName)
|
||||
assertEquals("TestSpam", modelToTestClass.className)
|
||||
assertEquals(dirPath, modelToTestClass.targetDir)
|
||||
assertEquals(modelToTestClass.methods, listOf("test_eggs", "test_eggs_and_ham"))
|
||||
|
||||
val modelToTestFunction = getModelForFunc()!!
|
||||
assertEquals("test_create_tst.py", modelToTestFunction.fileName)
|
||||
assertEquals("Test", modelToTestFunction.className)
|
||||
assertEquals(dirPath, modelToTestClass.targetDir)
|
||||
assertEquals(modelToTestFunction.methods, listOf("test_test_foo"))
|
||||
|
||||
val modelToTestEmptyClass = getModel("SpamSpamSpamBakedBeans")!!
|
||||
assertEquals("test_create_tst.py", modelToTestEmptyClass.fileName)
|
||||
assertEquals("TestSpamSpamSpamBakedBeans", modelToTestEmptyClass.className)
|
||||
assertEquals(dirPath, modelToTestEmptyClass.targetDir)
|
||||
assertEquals(modelToTestEmptyClass.methods, emptyList<String>())
|
||||
}
|
||||
|
||||
fun testWithPyTest() {
|
||||
service.projectConfiguration = PyTestFrameworkService.getSdkReadableNameByFramework(PyNames.PY_TEST)
|
||||
val modelToTestClass = getModel()!!
|
||||
assertEquals("test_create_tst.py", modelToTestClass.fileName)
|
||||
assertEquals("", modelToTestClass.className)
|
||||
assertEquals(dirPath, modelToTestClass.targetDir)
|
||||
assertEquals(modelToTestClass.methods, listOf("test_eggs", "test_eggs_and_ham"))
|
||||
|
||||
assertNull("test_foo is test from pytest point of view, can't test it", getModelForFunc())
|
||||
|
||||
val modelToTestEmptyClass = getModel("SpamSpamSpamBakedBeans")!!
|
||||
assertEquals("test_create_tst.py", modelToTestEmptyClass.fileName)
|
||||
assertEquals("", modelToTestEmptyClass.className)
|
||||
assertEquals(dirPath, modelToTestEmptyClass.targetDir)
|
||||
assertEquals(modelToTestEmptyClass.methods, listOf("test_spam_spam_spam_baked_beans"))
|
||||
}
|
||||
|
||||
fun testTestFolderDetected() {
|
||||
ApplicationManager.getApplication().invokeAndWait {
|
||||
WriteAction.runAndWait<Throwable> {
|
||||
VfsTestUtil.createDir(dir, testsFolderName)
|
||||
}
|
||||
}
|
||||
val modelToTestClass = getModel()!!
|
||||
assertEquals(dir.findChild(testsFolderName)!!.path, modelToTestClass.targetDir)
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
ApplicationManager.getApplication().invokeAndWait {
|
||||
WriteAction.runAndWait<Throwable> {
|
||||
dir.findChild(testsFolderName)?.delete(this)
|
||||
dir.findChild(testsFolderName)?.let { VfsTestUtil.deleteFile(it) }
|
||||
}
|
||||
}
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
private fun getModel(forClass: Boolean): PyTestCreationModel? {
|
||||
private fun getModelForFunc() = getModel(null)
|
||||
private fun getModel(forClass: String? = "Spam"): PyTestCreationModel? {
|
||||
val pyFile = myFixture.file as PyFile
|
||||
val element: PsiElement = if (forClass) pyFile.topLevelClasses[0] else pyFile.findTopLevelFunction("test_foo")!!
|
||||
val element: PsiElement = when {
|
||||
forClass != null -> pyFile.findTopLevelClass(forClass)!!
|
||||
else -> pyFile.findTopLevelFunction("test_foo")!!
|
||||
}
|
||||
return PyTestCreationModel.createByElement(element)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user