Coder avec Crystal pour ne pas perdre la boule, troisième partie
2020-10-12
Dernière modification le 2022-04-01Résumé de l'épisode précédent
C'est ici: deuxième partie
Nous avons ajouté quelques commandes à notre application pour pouvoir (enfin !) faire quelque chose d'utile avec. Elle nous permet de saisir des contacts et de les rechercher.
Le code correspondant à la fin de la deuxième partie est disponible à cette adresse, au tag partie-02.
Avant de reprendre
Crystal 0.35.1 est sorti !
Dirigez-vous vers la page d'installation pour installer cette nouvelle version.
Une petite bidouille avant de commencer les tests
Notre magnifique application écrit dans un fichier: ~/myapp.yaml
.
Quand nous lancerons nos tests, nous ne devons bien entendu utiliser un fichier temporaire.
Nous allons utiliser une variable d'environnement pour faire ça, à laquelle nous donnerons le doux nom de MYAPP_PATH
.
Nous pouvons donc modifier le fichier "src/lib/config.cr" et changer:
@@config_path : Path = Path.home / "myapp.yaml"
en
@@config_path : Path = Path[ENV.fetch("MYAPP_PATH", Path.home.to_s)] / "myapp.yaml"
L'API ENV permet d'accéder aux variables d'environnement, et nous utilisons ENV.fetch pour extraire la valeur de la variable "MYAPP_PATH". Le second argument est la valeur par défaut.
Testons notre application
Nous n'en n'avons pas encore parlé, mais lors de la génération de notre projet, les fichiers suivants ont été créés:
/spec/myapp_spec.cr
Ce fichier est un fichier de test, avec le contenu suivant:
require "./spec_helper"
describe Myapp do
# TODO: Write tests
it "works" do
false.should eq(true)
end
end
Nous allons supprimer ce fichier. Pas d'inquiétude, nous allons créer d'autres tests un peu plus loin.
/spec/spec_helper.cr
C'est un fichier d'aide dans lequel nous pourrons ajouter des fonctions utilitaires aux tests.
Par défaut, ce fichier inclut le module "spec" ainsi que le point d'entrée de l'application:
require "spec"
require "../src/myapp"
Nous allons remplacer ce contenu par le suivant:
require "file_utils"
require "spec"
ENV["MYAPP_PATH"] = File.join(Dir.tempdir, "myapp-spec-#{Random.new.hex(4)}")
FileUtils.mkdir_p(ENV["MYAPP_PATH"])
Ceci va nous permettre de créer un dossier temporaire pour le fichier myapp.yaml
et d'injecter son chemin dans la variable d'environnement MYAPP_PATH
.
Notre premier test !
Nous allons tester le fichier "src/lib/config.cr" qui permet de gérer notre liste de contacts.
Créons donc le fichier "spec/lib/config_spec.cr" avec le contenu suivant:
require "../spec_helper"
require "../../src/lib/config"
describe Myapp::Config do
config = Myapp::Config.new
describe "#add_contact" do
it "should work" do
config.contacts.size.should eq 0
contact = Myapp::Contact.new("Jane doe", ["janedoe@example.com"])
config.add_contact(contact)
config.contacts.size.should eq 1
end
end
end
Nous retrouvons les inclusions des fichiers "spec_helper" et "config", rien de surprenant jusque là.
Ensuite, pas de surprises avec les describe
et it
qui sont des mots clés très courants dans les frameworks de tests.
Dans le test en question, nous allons:
- Vérifier que la liste est vide au départ.
- Ajouter un contact.
- Vérifier que la liste contient un contact.
Ce qui est un peu curieux est l'apparition de .should
à la suite de size. Ceci vient du module "spec" qui augmente les objets !
Lancer les tests
On va utiliser la commande crystal spec
:
❯ crystal spec
.
Finished in 360 microseconds
1 examples, 0 failures, 0 errors, 0 pending
Le .
correspond à notre test qui fonctionne !
Il peut y avoir d'autres choses que des points:
F
quand le test ne passe pas.E
quand il y a une erreur.*
quand le test est en attente.
Cycle de vie
Comme pour la plupart des outils de tests, il y a un cycle de vie pour les tests (before_each, after_each) et les suites de tests (before_all, after_all) au niveau des fichiers de tests, ainsi que before_suite et after_suite au niveau de la suite (l'ensemble des tests).
Par exemple, modifions /spec/spec_helper.cr
pour ajouter les lignes suivantes:
Spec.after_suite do
FileUtils.rm_rf ENV["MYAPP_PATH"]
end
Maintenant, plus de pollution de /tmp avec nos fichiers de tests !
Une dépendance !
Nous avons déjà croisé la commande shards
ainsi que le fichier "shard.yml", qui contient un descriptif du projet et de ses dépendances.
Notre application mérite d'être un peu plus engageante, quoi de mieux pour ça d'y ajouter quelques émojis ?
Installation
Nous allons donc installer la dépendance emoji.cr en éditant le fichier "shard.yml":
dependencies:
emoji:
github: veelenga/emoji.cr
branch: master
Et un coup de shards
ou shards install
pour installer la dépendance.
Vous découvrirez un nouveau fichier "shard.lock" avec un contenu tel que celui-ci:
version: 2.0
shards:
emoji:
git: https://github.com/veelenga/emoji.cr.git
version: 0.4.0+git.commit.4642bd8ef64839b4639ba0be521e8c85113cb8d5
Si vous fouillez dans le dossier "lib", vous découvrirez le code de la dépendance qui vient d'être installée.
Utilisation
Nous allons modifier le fichier "src/commands/add.cr" pour ajouter la dépendance que nous allons utiliser. Il faut ajouter la ligne suivante en haut du fichier:
require "emoji"
Et nous modifions le message quand un nom n'a pas été donné.
Nous avons donc:
puts "We need a name!"
Qui devient
puts Emoji.emojize(":warning: We need a name!")
On vérifie que ça fonctionne
Nous allons construire l'application en utilisant shards build
à la racine du projet. Ensuite, cd bin/
et on lance notre application pour rentrer dans le cas que nous venons de modifier:
❯ ./myapp add email="pouet@example.com"
⚠️ We need a name!
Et voilà ! On a un émoji dans la console !
Et voilà !
Nous avons fait de tous petits pas avec Crystal, comment s'organise un petit projet, comment faire un test etc. C'est la fin de cette petite série. Amusez-vous bien avec Crystal !
Le code est disponible à cette adresse, au tag partie-03.