Saat proyek membesar, kita sering perlu memisahkan kode produksi dari kode pengujian, atau memisahkan kode yang berjalan di platform berbeda. Mekanisme Gradle untuk itu disebut source set. Pada chapter ini kita akan membahas konsep source set, source set bawaan (main dan test), cara mendefinisikan source set kustom, serta source set khusus Kotlin Multiplatform seperti commonMain dan jvmMain. Pemahaman ini penting untuk mengorganisasi proyek Gradle yang sehat.

Apa Itu Source Set #

Source set adalah kumpulan direktori sumber beserta konfigurasi dependensi yang di-compile menjadi output terpisah. Gradle secara default menyediakan dua source set:

  • main: kode produksi. Di-compile ke build/classes/kotlin/main.
  • test: kode uji. Di-compile ke build/classes/kotlin/test; hanya berjalan saat task test.

Kode pada test dapat memanggil kode main, tetapi tidak sebaliknya. Classpath kedua source set juga berbeda — test biasanya memiliki dependensi tambahan seperti JUnit, Kotest, atau MockK.

Struktur Direktori Standar #

Konvensi Gradle + Kotlin:

text
src/
├── main/
│   ├── kotlin/        ← kode produksi Kotlin
│   └── resources/     ← file resource (application.conf, dll.)
└── test/
    ├── kotlin/        ← kode uji Kotlin
    └── resources/     ← resource uji (fixture, file JSON)

Pada Kotlin Multiplatform (KMP), struktur diperluas dengan target:

text
src/
├── commonMain/kotlin/    ← kode lintas-platform
├── commonTest/kotlin/    ← uji kode commonMain
├── jvmMain/kotlin/       ← kode khusus JVM
├── jvmTest/kotlin/       ← uji kode jvmMain
├── jsMain/kotlin/        ← kode khusus JS
└── nativeMain/kotlin/    ← kode khusus Native

Contoh Kode #

Berikut program kecil yang memperlihatkan pemisahan logika produksi dan logika pengujian secara konseptual:

kotlin
// File: source_sets.kt
// Mendemonstrasikan konsep source set via simulasi runtime.
// Pada Gradle, source set adalah kumpulan direktori sumber yang di-compile
// menjadi output terpisah. Kotlin memperlakukan main/ dan test/ sebagai
// dua source set berbeda dengan classpath masing-masing.
package com.example.sourceset

import java.time.LocalDate

// Sumber di src/main/kotlin (production code).
data class ItemTugas(val judul: String, val tenggat: LocalDate, val selesai: Boolean = false) {
    fun ringkas(): String {
        val status = if (selesai) "selesai" else "belum"
        return "[$status] $judul — tenggat ${tenggat}"
    }
}

// Sumber di src/test/kotlin (test code). Pada proyek nyata fungsi ini
// ditempatkan pada source set test/ dan hanya di-compile saat test.
object TesSimulasi {
    fun verifikasiRingkas(): Boolean {
        val tugas = ItemTugas("Review", LocalDate.of(2026, 3, 1), selesai = true)
        return tugas.ringkas().contains("[selesai]")
    }
}

fun main() {
    val tugas1 = ItemTugas("Tulis laporan", LocalDate.of(2026, 3, 1))
    val tugas2 = ItemTugas("Review kode", LocalDate.of(2026, 3, 5), selesai = true)
    println(tugas1.ringkas())
    println(tugas2.ringkas())

    println("Tes verifikasi ringkas: ${TesSimulasi.verifikasiRingkas()}")

    println("Struktur source set:")
    println("  src/main/kotlin -> output: build/classes/kotlin/main")
    println("  src/test/kotlin -> output: build/classes/kotlin/test")
    println("  src/jvmMain/kotlin (KMP) -> build/classes/kotlin/jvmMain")
}

Output yang Dihasilkan:

text
[belum] Tulis laporan — tenggat 2026-03-01
[selesai] Review kode — tenggat 2026-03-05
Tes verifikasi ringkas: true
Struktur source set:
  src/main/kotlin -> output: build/classes/kotlin/main
  src/test/kotlin -> output: build/classes/kotlin/test
  src/jvmMain/kotlin (KMP) -> build/classes/kotlin/jvmMain

Mari kita bedah kode di atas:

  1. Baris 11 (data class ItemTugas): tipe produksi pada src/main/kotlin. Setiap file yang memakai ItemTugas pada main atau test dapat mengaksesnya karena test melihat classpath main.
  2. Baris 19-23 (object TesSimulasi): menunjukkan kode yang seharusnya berada pada src/test/kotlin. TesSimulasi.verifikasiRingkas() menguji method ringkas(). Pada proyek nyata, object ini akan ditempatkan pada file uji terpisah dan dianotasi @Test.
  3. Baris 25-33 (fun main): titik masuk produksi. Memakai ItemTugas dan TesSimulasi untuk demonstrasi.
  4. Baris 29-33 (println struktur source set): mencetak informasi struktur direktori source set agar pembaca melihat relasi sumber-output secara visual.

Source Set Kustom #

Kita dapat mendefinisikan source set kustom pada build.gradle.kts. Misalnya, untuk memisahkan kode demo:

kotlin build.gradle.kts: source set kustom
sourceSets {
    create("demo") {
        kotlin.srcDir("src/demo/kotlin")
    }
}

dependencies {
    "demoImplementation"(project(":core"))
    "demoImplementation"("io.github.microutils:kotlin-logging:3.0.5")
}

Konfigurasi di atas membuat source set demo dengan direktori sendiri dan dependensi sendiri. Output akan di-compile ke build/classes/kotlin/demo.

Source Set pada Kotlin Multiplatform #

Pada KMP, commonMain berisi kode yang berjalan di semua target. Source set target seperti jvmMain, jsMain, nativeMain berisi kode khusus platform. Kompilator memastikan bahwa kode commonMain tidak memakai API yang tidak tersedia di semua target.

Referensi Lanjutan #

  • Gradle — panduan resmi Gradle untuk Kotlin source set
  • Gradle User Guide — dokumentasi Gradle source set dan organisasi source
  • Version Catalogs — Gradle version catalogs untuk koordinasi dependency antar source set

Selanjutnya #

Setelah memahami source set, kita akan mendalami modifier internal yang merupakan penerapan langsung konsep modul dan source set — topik chapter internal Visibility.