PSI Tests for IntelliJ Plugin Developers
Often, plugin developers spend a lot of time figuring out their way around the PSI. The PSI APIs provide an elegant way to gather information, generate or manipulate source code. Though the PsiViewer Plugin comes in handy during development, it does not replace good old tests.
IntelliJ's testing framework serves a variety of needs. However, this post will only focus on testing logic that involves the PSI.
This post is to intended for a couple of purposes,
- I spent almost a day figuring out how to write tests for PSI traversal logic. With this information, you don't have to break a sweat.
- After trying out many approaches, this is the best way forward for me. I am curious to find out how others are approaching the same problem.
LightIdeaTestCase for PSI Tests
Most classes I came across in com.intellij.testFramework
package use JUnit 3, which includes LightIdeaTestCase
. Therefore, your PSI tests should be run by JUnit 3. That's a no-brainer.
The best way forward would be to bring in JUnit 5 (if you haven't already) for your tests because a preliminary search revealed no way to mix JUnit 3 tests with JUnit 4.
However, JUnit 5's Vintage Engine is capable of running both JUnit 3 and JUnit 4 tests. Yay!
First, ensure you have JUnit 5 setup correctly with at least the following dependencies.
JUnit 3 Tests
JUnit 3 existed even before Java added annotations to the language spec. Therefore, these tests look slightly different.
- They extend from a base class, usually
junit.framework.TestCase
. - The test method/function should be public and start with a
test
prefix.
These are the two things to remember before writing PSI tests.
Canary PSI Test
import com.google.common.truth.Truth.assertThat
import com.intellij.psi.PsiFileFactory
import com.intellij.testFramework.LightIdeaTestCase
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.KtFile
class CanaryPsiTest : LightIdeaTestCase() {
fun testCreatePsiFromPlainText() {
// given
val fileName = "Hello.kt"
val source = """
fun hello() {
println("Hello!")
}
""".trimIndent()
// when
val psiFile = PsiFileFactory
.getInstance(project)
.createFileFromText(fileName, KotlinLanguage.INSTANCE, source)
// then
assertThat(psiFile)
.isInstanceOf(KtFile::class.java)
}
}
The test extends LightIdeaTestCase
, which is a descendent of JUnit 3's TestCase
. The test function's name testCreatePsiFromPlainText
begins with the test
prefix.
The PsiFileFactory
can create a PsiFile
instance from any Language
you provide.
That's all you need to bring your PSI business logic under test for your IntelliJ Plugins. Do you test your PSI logic? If yes, how? Let me know @ragunathjawahar.