Le titre Kotlin prétendait être davantage associé au développement Android, mais pourquoi ne pas expérimenter? Avec son aide, nous avons trouvé un moyen de simplifier légèrement l'automatisation des tests de l'API de l'un de nos services, ainsi que de faciliter le travail des testeurs qui ne sont pas familiarisés avec la programmation et les nuances du langage Java.
Qu'est-ce que nous faisons? Nous développons un service d'envoi de questionnaires de courtage pour le calcul et la réception d'une décision à leur sujet. Et malgré le fait qu'il s'agisse d'une solution bancaire, le développement est réalisé par une petite équipe Scrum, dans laquelle 1 à 2 spécialistes sont impliqués dans les tests, en fonction de la charge et de la situation sur le projet.
Sous la coupe, nous vous parlerons des résultats de nos expériences, que nous avons volontiers transférés en production.
Pas de visage
Notre service a été développé pour s'intégrer à l'interface des partenaires et ne dispose pas de sa propre interface utilisateur. Par conséquent, dans ce cas, tester directement l'API est la seule option disponible. Bien que les tests d'API présentent un certain nombre d'avantages même avec une interface:
- vous permettent de commencer les tests dès le stade du développement des services;
- simplifier la localisation des erreurs;
- réduisent généralement le temps de test.
Notre service comprend un ensemble d'API pour le transfert des données du questionnaire client pour le calcul et pour l'obtention d'une solution pour un prêt automobile. Les contrôles suivants peuvent être distingués comme les principales tâches de test de haut niveau:
- format des champs et paramètres;
- l'exactitude des codes d'état et des messages d'erreur;
- champs obligatoires et logique de service.
Moment crucial
L'équipe a préparé le MVP du service en très peu de temps et les tests automatisés ont été initialement écrits par le développeur du produit. Il était plus rapide et plus pratique d'inclure des autotests dans le projet, donc au départ, ils étaient étroitement liés à son code et étaient basés sur la pile Java, assurée par REST et le framework de test TestNG.
Avec le développement du projet, l'implication des testeurs dans le processus d'automatisation s'est accrue. Pour le moment, les tâches de support et de mise à jour des autotests incombent entièrement au service des tests. À cet égard, il est devenu nécessaire d'ajuster l'approche de l'automatisation - pour simplifier au maximum les tests et les rendre indépendants du code principal. Et, ainsi, pour résoudre les difficultés qui surgissent:
- la communication avec le code rend les tests plus vulnérables à toute modification de conception, nécessite beaucoup de travail pour maintenir les performances;
- les relations complexes augmentent le temps nécessaire pour trouver des informations et enquêter sur les erreurs;
- Il est difficile d'impliquer de nouveaux employés du service de test dans le travail avec du code Java, cela nécessite une formation de testeurs et un temps important pour entrer dans le projet.
Par conséquent, nous avons décidé de changer l'approche des tests et avons formulé les exigences suivantes pour les nouveaux outils:
- compatibilité totale avec Java, qui vous permet de réécrire les contrôles par étapes, tout en continuant à travailler avec d'anciens tests;
- code simple et intuitif;
- langage libre et stable;
- sélection d'autotests dans un projet séparé.
Qu'est-ce que Kotlin a à voir avec ça
La langue Kotlin répond autant que possible à nos besoins.
Outre la compatibilité totale avec Java dans Kotlin, nous nous sommes intéressés aux fonctionnalités suivantes:
- la concision du langage rend le code clair et facile à lire;
- sucre syntactique;
- code intuitif et entrée facile des spécialistes dans le projet;
- la possibilité de transférer des autotests de Java à Kotlin progressivement et sans douleur, partiellement si nécessaire.
Bien sûr, il y a aussi des inconvénients, notamment par rapport à Java. Premièrement, une communauté relativement petite: trouver de l'aide et des réponses aux questions Java est beaucoup plus facile qu'avec Kotlin. Deuxièmement, en général, Java est un langage plus universel avec plus de capacités et un grand nombre de développements et de bibliothèques.
Mais, franchement, à des fins de test, nous n'avons pas besoin de capacités aussi étendues que seul Java peut fournir. Par conséquent, nous avons préféré la simplicité et la brièveté de Kotlin.
Des paroles aux actes
À la suite d'une transition partielle vers une nouvelle langue, nous avons obtenu un gain notable de coûts de main-d'œuvre pour les spécialistes, une simplification significative du code et une réduction de son volume. Cela se voit clairement dans des exemples spécifiques de tests de notre service de traitement des profils de courtage.
Dans Kotlin, vous pouvez initialiser un objet de requête avec une ligne de code. Par exemple, la classe ApplicationDTO (pour envoyer un questionnaire à la solution) et ErrorDTO (erreurs provenant du service) ressemblent à ceci:
Kotlin vous permet de définir des valeurs de champ lors de l'initialisation. Cela permet de gagner beaucoup de temps lors de l'écriture des tests: lors de la création d'un objet, les champs sont déjà remplis avec des données valides, on ne change que les valeurs qui se réfèrent au contrôle en cours.
L'annotation JsonIgnoreProperties vous permet de ne pas spécifier tous les champs d'une classe s'ils ne sont pas nécessaires pour les tests et n'ont pas besoin d'être vérifiés. Si un champ est reçu qui n'est pas spécifié dans la description, le test n'échouera pas avec une erreur.
Le point d'interrogation au niveau du type d'une variable indique qu'à un moment donné, elle peut être nulle. Mais lors de l'utilisation d'une variable, cela devra être pris en compte et traité. Enfin, contrairement aux tests Java, NullPointerException peut être évité gracieusement ici.
Illustrons avec un exemple simple de vérification d'erreur pour une connexion incorrecte:
class ApplicationTests {
val DEFAULT_LOGIN = "consLogin"
val ERROR_CODE = "3"
val BASE_URI = "https://base_url.com"
@Test
fun incorrectLogin() {
val incorrectLogin = DEFAULT_LOGIN + "INCORRECT";
val res = given()
.spec(spec)
.body(ApplicationDTO)
.`when`()
.post(endpointApplication(incorrectLogin)
.then()
.statusCode(400)
.extract().`as`(ErrorDTO::class.java)
assertThat(res.error_message).containsIgnoringCase(" ")
assertThat(res.error_code).isEqualToIgnoringCase(ERROR_CODE)
}
companion object{
private var spec: RequestSpecification? = null
@JvmStatic
@BeforeClass
fun initSpec() {
spec = RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setBaseUri(BASE_URI)
.addFilter(ResponseLoggingFilter())
.addFilter(RequestLoggingFilter())
.build()
}
}
}
Nous créons une spécification pour les requêtes dans BeforeClass, que nous réutilisons dans tous les tests de cette classe. Jackson sérialise et désérialise les objets json, ce qui simplifie les choses: vous n'avez pas besoin de travailler avec eux comme avec des chaînes, à cause de cela, le nombre d'erreurs est considérablement réduit.
Avec Kotlin, nous réduisons considérablement la quantité de code, ce qui signifie que nous facilitons la vie des «écrivains» et des «lecteurs». La classe ApplicationDTO contient déjà un constructeur et quelques autres méthodes (hashCode (), copy (), etc.) - nous n'avons pas besoin de "surcharger" le code avec eux et les développeurs de tests automatiques novices ne sont pas distraits par eux. Ils n'ont pas besoin d'être mis à jour en cas de modification, ce qui réduit le temps de modification des tests.
Il est également très pratique que Kotlin supporte les arguments nommés - le code est assez facile à lire, et il n'est pas nécessaire d'écrire des setters pour les classes d'objets json vous-même.
Essayez de nouvelles choses gratuitement
Je tiens à souligner l'ouverture et la franchise de Kotlin et de toutes les bibliothèques que nous utilisons, ce qui simplifie grandement le travail et élargit les possibilités d'expérimentation et d'introduction de nouvelles approches. D'accord, il est toujours plus facile d'essayer de nouvelles choses gratuitement, et en cas d'échec, de revenir aux anciennes pratiques.
À l'avenir, nous prévoyons de développer une nouvelle approche et de l'adapter à d'autres projets, de traduire le reste des tests d'API et d'interface utilisateur vers Kotlin.
PS: Malgré le fait que Kotlin soit principalement associé au développement Android, la portée de son utilisation, comme vous le comprenez, ne se limite pas à cela. En réduisant le temps passé à écrire du code, sa simplicité et sa concision aideront à réduire les coûts de main-d'œuvre pour résoudre de nombreux problèmes. Si nous avons de nouveaux cas avec Kotlin, nous vous en parlerons certainement.ici .