DEV Community

David YOTEAU
David YOTEAU

Posted on

Exploration de l'API Standard de Crystal-lang PART 2 (Spec, ENV, Module)

Introduction

Voici la partie 2 de notre série. il est nécessaire d'avoir lu la partie précédente pour suivre cet article.

Dans cet article, nous allons voir :

  • Spec librairie interne de test
  • Les modules.
  • ENV Manipulation des variables d'environnement

C'est parti

lançons les tests - premier essai.

La commande de test est crystal spec. Cette commande va exécuter les test contenus dans tous les fichier _spec.cr de toutes l'arborescence ./spec/**/*.

Voici le code par défaut, qui a été généré avec le crystal init dans le fichier ./spec/web_spec.cr

describe Web do 
  # TODO: Write tests

  it "works" do
    false.should eq(true)
  end 
end
Enter fullscreen mode Exit fullscreen mode

describe est un mot clé pour décrire une suite de test. Nous pouvons lui passer en argument soit une chaîne de caractère soit le nom d'un objet. Nous pouvons ecrire un autre bloc describe dans celui existant. Cela aura pour effet de se concaténer.

Dans notre cas, l'objet Web n'existe pas. la commande crystal spec va nous répondre une erreur.

it est le bloc de test. Nous lui passons une chaîne de caractère en argument. Chaîne qui doit décrire le test. Par convention, si le test concerne une méthode de l'objet passer en describe, nous préfixons le nom de la méthode par un #

Ensuite, nous pouvons voir que le test écrit est voué à l’échec false ne valant jamais true.

Corrigeons ces deux points et regardons ce qui ce passe...

Dans l'état actuel des choses, il ne se passera rien et votre crystal spec restera bloqué. Il faudra un CTRL+C pour sortir.

Voici ce qu'il se passe. Notre fichier ./spec/web_spec.cr charge le fichier ./spec/spec_helper.cr. Ce dernier charge notre code du fichier ./src/web.cr. Or, notre code lance un serveur HTTP et attend en boucle les requêtes. C'est ce qui bloque notre test.

Deux solutions s'offre à nous pour l'instant.

Rapide : Nous sortons la commande server.listen dans un autre fichier. Et nous lancerons ce nouveau fichier quand nous voudrons lancer le serveur.

Par configuration : Nous conditionnons le lancement de server.listen au fait de ne pas être en environnement de test.

Dans notre cas, nous partons sur la première solution pour évoluer vers la seconde.

Testons notre configuration.

Dans le code actuel, nous avons quelques constantes au début :

TODO_FILE_PATH = File.join(Dir.current, "todo.txt")
Enter fullscreen mode Exit fullscreen mode

et quelques valeurs en dur pour la configuration de notre serveur http

server.bind_tcp "0.0.0.0", 8080
Enter fullscreen mode Exit fullscreen mode

et comme nous venons de le voir, nous avons aussi besoin de déterminer dans quel environnement nous sommes.

Supprimons le fichier ./spec/web_spec.cr qui ne nous sert pas. Créons un fichier ./spec/config_spec.cr.

Commençons l’écriture de notre test, nous avons besoin d'un objet qui va stocker notre configuration et permettre un accès dans tout notre code.

La première constante va être TODO_FILE_PATH.

require "./spec_helper"

describe Config do
  describe "#TODO_FILE_PATH" do
    pending "return a path by concat current dir with 'todo.txt' do
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

le mot clé pending permet ne pas exécuter ce test tout en gardant la structure pour plus tard.

Passons à l’écriture du test et du module

  require "./spec_helper"

  describe Config do
    describe "#TODO_FILE_PATH" do
      it "return a path by concat current dir and todo_file_name" do                             
        Config::TODO_FILE_PATH.should eq File.join(Dir.current, "todo.txt")
      end
    end
  end
Enter fullscreen mode Exit fullscreen mode

ce qui se résout par le code suivant :

  module Config
    TODO_FILE_PATH = ENV.fetch("TODO_FILE_PATH", File.join(Dir.current, "todo.txt"))
  end
Enter fullscreen mode Exit fullscreen mode

Crystal vient avec la librairie standard ENV qui permet de lire et de manipuler les variables d'environnement.

J'ai écris le code du module config dans le fichier src/web.cr. Nous allons le déplacer dans son propre fichier src/config.cr et le charger dans son fichier d'origine.

# src/web.cr
require "http/server"
require "./config"
...
Enter fullscreen mode Exit fullscreen mode

On remplace toutes les occurrences de TODO_FILE_PATH par Config::TODO_FILE_PATH

Continuons avec les variables du serveur http et l'environnement.

Le test

  require "./spec_helper"

  describe Config do
    describe "#TODO_FILE_PATH" do
      it "return a path by concat current dir and todo_file_name" do
        Config::TODO_FILE_PATH.should eq File.join(Dir.current, "todo.txt")
      end
    end

    describe "#environment" do
      it "return development as default environment" do
        ENV.delete("GTD_ENVIRONMENT")
        Config.environment.should eq "development"
      end
      it "return passed value as environment" do
        ENV["GTD_ENVIRONMENT"]= "test"
        Config.environment.should eq "test"
        ENV.delete("GTD_ENVIRONMENT")
      end
    end

    describe "#PORT" do
      it "return default port" do
        Config::PORT.should eq 3000
      end
    end

    describe "#BIND_IP" do
      it "return default binding" do
        Config::BIND_IP.should eq "0.0.0.0"
      end
    end
  end
Enter fullscreen mode Exit fullscreen mode

le module

  module Config
    TODO_FILE_PATH = ENV.fetch("TODO_FILE_PATH", File.join(Dir.current, "todo.txt"))
    PORT = ENV.fetch("PORT", "3000").to_i
    BIND_IP = ENV.fetch("BIND_IP", "0.0.0.0")

    def self.environment
      ENV.fetch("GTD_ENVIRONMENT", "development")
    end
  end
Enter fullscreen mode Exit fullscreen mode

tous les tests sont passant.

Lancement du serveur sauf pour les tests.

Revenons à notre deuxième solution de gestion du lancement du serveur maintenant que nous avons le module de configuration.

Supprimons le fichier créer pour la première solution.

Puis, à la fin du fichier src/web.cr ajoutons notre condition de lancement.

  server.bind_tcp Config::BIND_IP, Config::PORT
  if Config.environment != "test"
    server.listen
  end
Enter fullscreen mode Exit fullscreen mode

Si nous lançons notre code avec crystal src/web.cr, nous avons bien notre application disponible via http://localhost:3000/

si je lance les tests avec la commande GTD_ENVIRONMENT=test crystal spec, les tests se lancent sans le serveur.

Il peut être lassant d'ajouter la variable d'environnement à chaque lancement. Pour ma part, j'ai ajouté cette variable dans le fichier ./spec/spec_helper.cr comme suit :

  require "spec"
  ENV["GTD_ENVIRONMENT"]="test"
  require "../src/web"
Enter fullscreen mode Exit fullscreen mode

Conclusion

Nous avons vu les bases de Spec, la manipulation de l'environnement via ENV et la forme d'objet Module.

Dans le prochain article, nous regrouperons les méthodes liées au dépôt de tâches au sein d'une classe

Note :

repository gitlab

Top comments (0)