Démarrer avec Kotlin
J’ai remarqué que peu de développeurs savaient bootstrap un nouveau projet. La preuve en est pour Kotlin, où j’ai dû demander à plusieurs développeurs avant d’obtenir l’aide de Cédric pour régler une broutille. Vu que j’aime faire des petits ateliers de code et également en animer, des katas par exemple, je me suis dit que ce serait pratique d’avoir un guide de démarrage rapide, avec l’essentiel pour m’en rappeler ou pour le donner aux participants d’un atelier. Des choses comme la création du projet, l’ajout de dépendances, les différents tests, et quelques liens utiles.
Voici donc un premier guide pour Kotlin. Je le partage pour m’aider moi ou quiconque voudra se lancer rapidement dans un petit projet de code avec des tests. C’est un essentiel à l’instant T, je le mettrais possiblement à jour dans le temps avec de nouvelles choses. Si vous avez des remarques, je suis preneur.
Création d’un projet
Il existe d’autres solutions, mais je ne parlerais que de Gradle qui est plus récent et qui est recommandé.
Via Intellij IDEA
JetBrains a créé le langage et l’outillage. La création d’un projet Kotlin est simple et rapide. On passe par le menu : File > New > Project.
Les possibilités changent ensuite selon l’édition de Intellij et/ou du système d’exploitation je suppose.
Si vous avez la possibilité, sélectionnez Kotlin puis Console Application. Gradle y sera ajouté par défaut. La documentation officielle va dans ce sens. Sinon, si vous êtes comme moi sur macOS avec l’édition Intellij IDEA CE, sélectionnez Gradle puis cochez Kotlin/JVM.
Plus d’informations : https://kotlinlang.org/docs/jvm-get-started.html
En ligne de commande
La simplicité est également présente en ligne de commande. Il suffit d’exécuter gradle init
puis de se laisser guider. Ce que je choisis en général :
- Type of project : application.
- Implementation language : Kotlin.
- Script DSL : Groovy ou Kotlin.
Exécution du projet et des tests
Via Intellij IDEA
D’un clic-droit sur un module ou un fichier dans l’arborescence, il est possible de compiler le projet, lancer le projet, et lancer les tests.
Les résultats des tests sont visibles dans un des onglets du bas d’Intellij IDEA. Il est possible de voir tous les tests, ou de filtrer selon le succès ou l’échec.
⚠️ Kotest : Parfois, il faut aller sur le menu latéral « Gradle » et cliquer sur Tasks > verification > test. Lancer la tâche « test » manuellement pour voir tous les tests se lancer. Problème dû à kotest ou à la présence de plusieurs frameworks de tests ?
En ligne de commande
Le projet étant créé avec Gradle, on passera toujours par la commande gradle
pour effectuer des actions.
- Lancer les tests :
gradle test
- Lancer les tests automatiquement (watch mode) :
gradle test —continuous
- Lancer l’application :
gradle run
Choix de l’IDE
Intellij IDEA
Sans hésiter, je dirais d’utiliser Intellij IDEA. JetBrains a un très bon savoir-faire. L’IDE est très complet en termes de fonctionnalités, les possibilités de refactoring sont nombreuses, et l’écosystème Kotlin est très bien intégré. La version communautaire est en plus gratuite.
On trouve toutes les options de refactoring à l’aide du raccourci Ctrl + T
.
Gestion des dépendances
Le fichier de configuration principal est build.gradle
(Groovy) ou build.gradle.kts
(Kotlin).
Pour ajouter des dépendances, on est souvent amené à insérer des lignes dans l’étape nommée dependencies
. Par exemple :
dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
}
⚠️ Lorsque l’on ajoute une nouvelle dépendance, il faut vérifier que celle-ci ne va pas entrer en conflit ou n’est pas en double (sous une autre version). Ce peut être le cas lorsque l’on initialise le projet en ligne de commande et que l’on ajoute les dépendances de JUnit. L’erreur est difficilement visible : au lancement des tests, aucun d’eux n’est trouvé.
⚠️ Il existe plusieurs sources pour récupérer les dépendances : les repositories
. Il peut être nécessaire de changer ou d’ajouter une source pour résoudre les dépendances.
⚠️ Après un changement dans le fichier de configuration, il peut être nécessaire de recharger Gradle dans Intellij IDEA. Une petite icône Gradle est peut-être apparue par-dessus le contenu du fichier.
Variables
On peut définir des variables dans le fichier de configuration. Exemple en Groovy :
def kotestversion = '4.4.3'
dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
}
⚠️ Les variables ne peuvent pas figurer dès le début du fichier.
⚠️ Il faut faire attention à bien utiliser les double quotes. Certaines documentations comme celle de kotest donnent des instructions qui ne compilent pas.
Écrire des tests unitaires
Tests unitaires classiques
JUnit fonctionne très bien avec Kotlin sur JVM. Il suffit d’annoter la fonction avec @Test
et d’utiliser un des assert
. Voir documentation officielle pour ajouter la dépendance.
@Test
fun testSum() {
val expected = 43
assertEquals(expected, classForTesting.sum(40, 2))
}
Assertions et matchers
JUnit propose quelques assert
classiques. On peut y ajouter les matchers de Kotest (une des sous-dépendances) pour avoir davantage de possibilités.
name shouldBe "sam"
"substring".shouldContain("str")
.shouldBeLowerCase()
mylist.forExactly(3) {
it.city shouldBe "Chicago"
}
Parameterized tests
JUnit propose un moyen de rendre une fonction de test paramétrable grâce aux annotations @ParameterizedTest
et @MethodSource
. La fonction de test acceptera alors des paramètres en entrée pour jouer le scénario avec différentes valeurs. Kotest le permet également à sa façon.
internal class MarsRoverTest {
companion object {
@JvmStatic
fun leftCommands() = listOf(
Arguments.of("N", "W"),
Arguments.of("W", "S"),
Arguments.of("E", "N"),
Arguments.of("S", "E")
)
}
@ParameterizedTest(name = "The new direction is {1} with initial direction {0}")
@MethodSource(value = ["leftCommands"])
internal fun `Should turn left`(initialDirection: String, newDirection: String) {
val world = World(3,3)
val marsRover = MarsRover(position, initialDirection, world)
marsRover.execute(listOf("L"))
marsRover.direction shouldBe newDirection
}
}
Property-based Testing
Kotest permet de faire du Property-based Testing via de nombreux générateurs et apporte plusieurs fonctionnalités (shrinking, repeatable random seeds, …). Ajout de la dépendance et utilisations sur la documentation officielle.
class PropertyExample: StringSpec({
"String size" {
checkAll<String, String> { a, b ->
(a + b).length shouldHaveLength a.length + b.length
}
}
})
Code Coverage
Plus tard :)
Mutation Testing
Plus tard :)
Apprendre le langage
Selon les goûts et les couleurs, voici plusieurs moyen d’apprendre Kotlin.
La documentation officielle. On y trouve un tas d’explications, d’exercices et de ressources autour du langage.
Les Koans. De petits exercices pour apprendre par petites étapes, en étant guidé dans différents thèmes.
Learn X in Y minutes sur Kotlin. Un condensé de ce qu’il faut savoir sur n’importe quel langage.
La convention de code officielle. Afin de ne pas se faire taper dessus par les puristes.
REPL
Plus tard :)