テストガイド¶
テストの実行¶
# Run all tests
./gradlew test
# Run tests with coverage report
./gradlew test koverHtmlReport
# View coverage report
open build/reports/kover/html/index.html
テスト構成¶
テストは src/test/kotlin/com/rescript/plugin/ に配置され、ソースコードのパッケージ構成をミラーしています:
src/test/kotlin/com/rescript/plugin/
├── highlight/
│ ├── RescriptSyntaxHighlighterTest.kt
│ └── RescriptBraceMatcherTest.kt
├── lang/
│ ├── RescriptLexerTest.kt
│ └── RescriptParserTest.kt
├── folding/
│ └── RescriptFoldingBuilderTest.kt
├── ...
テストの作成¶
テスト規約¶
ファイル命名:
<TargetClass>Test.kt配置場所: テスト対象クラスと同じパッケージ
フレームワーク: JUnit 5 と IntelliJ テストフィクスチャ
IntelliJ テストフィクスチャ¶
ほとんどのテストは IntelliJ Platform のテスト基底クラスを継承しています:
class RescriptMyFeatureTest : BasePlatformTestCase() {
override fun getTestDataPath(): String = "src/test/testData/myfeature"
fun testBasicCase() {
// Configure test fixture with a ReScript file
myFixture.configureByText("Test.res", "let x = 1")
// Invoke the feature and assert results
}
}
テストデータファイル¶
テストデータファイルは src/test/testData/<feature>/ に配置します:
src/test/testData/
├── folding/
│ ├── module.res
│ └── comments.res
├── highlighting/
│ └── keywords.res
└── ...
レクサーテスト¶
レクサーが正しいトークンシーケンスを生成することをテストします:
fun testKeywords() {
val lexer = RescriptLexer()
lexer.start("let x = 1")
assertEquals(RescriptTokenTypes.LET, lexer.tokenType)
lexer.advance()
// ... continue checking tokens
}
パーサーテスト¶
パーサーが正しい PSI 構造を生成することをテストします:
fun testLetDeclaration() {
myFixture.configureByText("Test.res", "let x = 1")
val file = myFixture.file
val declarations = PsiTreeUtil.findChildrenOfType(file, RescriptLetDeclaration::class.java)
assertEquals(1, declarations.size)
}
統合テスト¶
統合テストは IntelliJ Platform のテストインフラを使用して、PSI ツリー、エディタフィクスチャ、ファイルベースのテストデータを含む実際の IDE 環境で機能を検証します。
ユニットテストと統合テストの比較¶
観点 |
ユニットテスト |
統合テスト |
|---|---|---|
基底クラス |
なし、または素の JUnit |
|
速度 |
高速(IDE の起動不要) |
低速(IDE プラットフォームの初期化あり) |
スコープ |
単一のクラス / 関数 |
IDE コンテキストでの機能のエンドツーエンド |
使用する場面 |
純粋なロジックのテスト(レクサートークン、ユーティリティ関数) |
PSI、エディタ、またはフィクスチャと連携する機能のテスト |
BasePlatformTestCase パターン¶
統合テストは BasePlatformTestCase を継承します。このクラスはエディタ、PSI インフラ、プロジェクトモデルを備えた軽量な IDE 環境を起動します:
class RescriptMyFeatureIntegrationTest : BasePlatformTestCase() {
override fun getTestDataPath(): String = "src/test/testData/myfeature"
fun testFeatureWithInlineCode() {
// Configure editor with inline ReScript code
myFixture.configureByText("Test.res", """
let x = 1
module M = {
let y = 2
}
""".trimIndent())
// Invoke the feature and assert results
// e.g., myFixture.testStructureView { ... }
}
fun testFeatureWithTestDataFile() {
// Load a test data file from getTestDataPath()
myFixture.configureByFile("Example.res")
// Assert against the loaded file
}
}
主要なメソッド:
myFixture.configureByText(filename, content)— メモリ上にファイルを作成し、エディタで開くmyFixture.configureByFile(filename)—testDataPathディレクトリからファイルを読み込むmyFixture.testStructureView { view -> ... }— ストラクチャービューを開き、その内容を検証するmyFixture.testHighlighting(...)— ハイライトを実行し、アノテーションを確認する
統合テストクラス¶
プロジェクトには以下の統合テストカテゴリが含まれています:
テストクラス |
機能 |
アサーション例 |
|---|---|---|
|
シンタックスハイライト |
トークンの色が期待される属性と一致する |
|
コード折りたたみ |
折りたたみ領域がテストデータ内の |
|
ストラクチャービュー |
ツリーに期待される宣言が含まれている |
|
自動インデント |
Enter キー押下後のインデントレベル |
|
パーサー + PSI ツリー |
PSI ツリーが期待される構造と一致する |
|
レクサートークンストリーム |
ファイル全体のトークンシーケンスが期待値と一致する |
testData ディレクトリ¶
テストデータファイルは src/test/testData/ 配下に機能ごとに整理されています:
src/test/testData/
├── folding/ # .res files with <fold> markers
├── highlighting/ # .res files for highlighting tests
├── structure/ # .res files for structure view tests
├── indent/ # .res files for indentation tests
├── parser/ # .res files for parser tests
└── lexer/ # .res files for lexer tests
各テストクラスは getTestDataPath() でデータディレクトリを指定します。テストデータファイルは通常の .res ファイルで、フレームワーク支援のアサーション用に特殊なマーカー(例: <fold text="...">)が含まれる場合があります。
テストカバレッジ¶
プロジェクトはコードカバレッジに Kover を使用しています。
# Generate HTML report
./gradlew koverHtmlReport
# Generate XML report (used by CI)
./gradlew koverXmlReport
カバレッジレポートは build/reports/kover/html/ に生成されます。
カバレッジ要件¶
新しいコードにはテストカバレッジが必要です
CI がプルリクエストでカバレッジを報告します
例外: UI コンポーネント (Swing)、実行中のサーバーが必要な LSP 統合クラス
UI テスト (Remote-Robot)¶
プロジェクトには、エンドツーエンドの IDE テストと Marketplace 用スクリーンショットの自動キャプチャのために IntelliJ Remote-Robot を使用した UI テストが含まれています。
前提条件¶
macOS: Java にアクセシビリティ権限を付与してください(システム設定 > プライバシーとセキュリティ > アクセシビリティ)
src/uiTest/testData/sample-project/のサンプルプロジェクトに npm 依存関係をインストールしておく必要があります:
cd src/uiTest/testData/sample-project
npm install
UI テストの実行¶
UI テストは 2 段階のプロセスが必要です — テストが接続する前に IDE が起動している必要があります:
# Terminal 1: Start the IDE with Remote-Robot server (port 8082)
./gradlew runIdeForUiTests
# Terminal 2: Open the sample project in the IDE, then run the tests
./gradlew uiTest
スクリーンショット出力¶
MarketplaceScreenshotTest クラスは、プラグインの主要機能を紹介する 11 枚のスクリーンショットをキャプチャします。スクリーンショットは build/screenshots/ に保存されます:
スクリーンショット |
機能 |
|---|---|
|
ReScript コードの色付け |
|
LSP 補完ポップアップ |
|
インラインのエラー/警告表示 |
|
型推論ヒント |
|
ファイルシンボルツリー |
|
関数の型注釈 |
|
JSX シンタックスハイライト |
|
.resi ネストとコンパイル済み JS |
|
Alt+Enter インテンションメニュー |
|
型情報とドキュメント |
|
インタラクティブ REPL ツールウィンドウ |
テスト構成¶
UI テストは別のソースセット(src/uiTest/)にあり、./gradlew test では実行されません:
src/uiTest/kotlin/com/rescript/plugin/uitest/
├── UiTestBase.kt # Base class (connection, screenshots)
├── fixtures/
│ └── IdeFixtures.kt # IDE component fixtures
└── screenshot/
└── MarketplaceScreenshotTest.kt # Marketplace screenshot capture
備考¶
UI テストは CI に含まれていません(ディスプレイが必要なため)
uiTestソースセットは Kover カバレッジから除外されていますスクリーンショットは Marketplace での見栄えのために Darcula テーマを使用しています
CI テスト¶
CI パイプラインはすべてのプッシュと PR で自動的にテストを実行します:
./gradlew test koverXmlReport koverHtmlReportKover レポートアクションを通じて PR でカバレッジが報告されます
テスト結果はアーティファクトとしてアップロードされます