writing-tests
Writing Tests
Guidelines for writing tests in IntelliJ IDEA codebase.
For examples, see community/platform/testFramework/junit5/test/showcase/.
Prefer JUnit 5 over JUnit 4
Use JUnit 5 with @TestApplication annotation instead of extending LightJavaCodeInsightFixtureTestCase.
Why JUnit 5:
- Faster: No class hierarchy overhead, shared fixtures via companion objects
- Cleaner: Annotations (
@TestDisposable,@RegistryKey) instead of manual setup/teardown - Flexible: Mix EDT and non-EDT tests in one class, parameterized tests, nested tests
- Better isolation: Each test gets fresh disposables automatically
Shared Fixtures Pattern
Use companion object fixtures shared between all tests:
@TestApplication
internal class MyTest {
companion object {
private val projectFixture = projectFixture()
private val moduleFixture = projectFixture.moduleFixture("src")
}
private val project get() = projectFixture.get()
private val module get() = moduleFixture.get()
}
Lifecycle Hooks
Use JUnit 5 lifecycle annotations for setup and teardown:
@TestApplication
internal class MyTest {
companion object {
@JvmStatic
@BeforeAll
fun setUpClass() {
// Once before all tests in class
}
@JvmStatic
@AfterAll
fun tearDownClass() {
// Once after all tests in class
}
}
@BeforeEach
fun setUp() {
// Before each test method
}
@AfterEach
fun tearDown() {
// After each test method
}
}
Note: Prefer @TestDisposable over manual @AfterEach cleanup for resources.
Test Disposables
Use @TestDisposable annotation to inject test-scoped disposables (created before each test, disposed after):
@TestDisposable
lateinit var disposable: Disposable
// Or as parameter
@Test
fun myTest(@TestDisposable disposable: Disposable) { ... }
Registry Values in Tests
Use @RegistryKey annotation instead of Registry.get().setValue():
@Test
@RegistryKey(key = "my.registry.key", value = "true")
fun testWithRegistryEnabled() { ... }
System Properties in Tests
Use @SystemProperty annotation instead of System.setProperty():
@Test
@SystemProperty(propertyKey = "my.property", propertyValue = "value")
fun testWithSystemProperty() { ... }
Running Tests in EDT
Use @RunInEdt annotation to run test methods in EDT:
@TestApplication
@RunInEdt
class MyEdtTest {
@Test
fun testInEdt() { ... }
}
// Or for specific methods only
@TestApplication
@RunInEdt(allMethods = false)
class MyTest {
@Test
@RunMethodInEdt
fun testInEdt() { ... }
}
Key Classes
com.intellij.testFramework.junit5.TestApplication- initializes shared applicationcom.intellij.testFramework.junit5.TestDisposable- injects test disposablescom.intellij.testFramework.junit5.RegistryKey- sets registry valuescom.intellij.testFramework.junit5.SystemProperty- sets system propertiescom.intellij.testFramework.junit5.RunInEdt- runs tests in EDTcom.intellij.testFramework.junit5.fixture.projectFixture- creates project fixturescom.intellij.testFramework.junit5.fixture.moduleFixture- creates module fixtures
Showcase Tests
JUnit5ProjectFixtureTest.kt- project fixture patternsJUnit5DisposableTest.kt- disposable injectionJUnit5SystemPropertyTest.kt- system property usageJUnit5RunInEdtTest.java- EDT execution
Running Tests
To run tests via command line, see TESTING.md.
Quick example:
./tests.cmd -Dintellij.build.test.patterns=*MyTest