Tests Rails - Comment s'affranchir du passé ?

Publié le 29 août 2022 par Willow Barraco

Cet article est publié sous licence CC BY-NC-SA

Récemment j’ai travaillé sur un nouveau projet qui a déjà toute une batterie de tests présente et je me suis heurtée à une problématique :

Comment ajouter de nouveaux tests, avec de nouvelles fixtures, sans risquer de casser les tests existants ?

Typiquement lorsque j’ai voulu ajouter des fixtures pour mes nouveaux tests, les anciens ne passaient plus, car ils n’ont pas été assez bien pensés initialement. Au lieu d’investir davantage de temps à réécrire ces tests existants j’aimerais rendre indépendant mes nouveaux tests des anciennes données.

Pour m’affranchir de cette contrainte et pouvoir ajouter de nouveaux tests en toute sérénité, j’ai eu envie d’utiliser un genre de contexte. D’écrire mes tests et fixtures dans un nouveau dossier bien séparé de l’existant. L’idée semble simple en apparence, mais en vérité, j’ai passé plusieurs jours à me casser la tête dessus. Les fixtures au sein d’une application Rails sont faites pour fonctionner facilement sans configuration mais dès qu’on essaie d’être originaux on est vite bloqués.

Voici donc, humblement, la solution que j’ai adoptée. Il existe probablement d’autres façons de faire, mieux ou pire. Moi j’ai trouvé ça !

J’ai développé de nouvelles fonctionnalités autour d’un projet client que l’on nommera ici Address Book. J’ai aussi en tête que j’aurai sans doute besoin d’ajouter de nouveaux contextes de tests à l’avenir. J’ai donc créé le dossier test/contexts/address_book/, racine de mon contexte :

# test/contexts/address_book/address_book_test_helper.rb

require_relative '../../../config/environment'
require 'rails/test_help'

class ActiveSupport::AddressBookIntegrationTest < ActionDispatch::IntegrationTest
  self.fixture_path = "#{Rails.root}/test/contexts/address_book/fixtures/"

  self.use_transactional_tests = false

  fixtures :all
end

Grace à fixture_path, les fixtures se trouvant dans le dossier fixtures/ du dossier de mon contexte seront utilisées.

J’ai également dû désactiver use_transactional_tests car la commande utilisée pour lancer les tests est $ rake db:drop; rake db:create && rake db:structure:load && rake db:fixtures:load && rake test ALL=yes BACKTRACE=yes. Les fixtures sont donc chargées avant les tests et chaque test va déclencher un rollback de la base de données. Or mes tests utilisent un contexte différent donc si je ne désactive pas cela mes nouvelles fixtures seront rollback.

Je peux maintenant utiliser ce AddressBookIntegrationTest comme base pour mes tests d’intégration :

# test/contexts/address_book/fixtures/contacts.yml

jeremy:
    address_1: "Rue de la ré"
    address_2: "Au rez de chaussé"
    zip_code: "69001"
    city: "Lyon"
    country: "France"
    phone: "+33423434565",
    mobile_phone: "+33623434565",
    email: "jeremy@yopmail.com"
# test/contexts/address_book/contact_test_helper.rb

require_relative "address_book_test_helper"

class ContactTest < ActiveSupport::AddressBookIntegrationTest
  test "using a basic contact" do
    get(
      "/api/v2/contacts/#{contacts(:jeremy).email}",
    )

    expected = {
      "id" => contacts(:jeremy).id,
      "address_1" => "Rue de la ré",
      "address_2" => "Au rez de chaussé",
      "zip_code" => "69001",
      "city" => "Lyon",
      "country" => "France",
      "phone" => "+33423434565",
      "mobile_phone" => "+33623434565",
      "email" => "jeremy@yopmail.com"
    }


    assert_response :success
    assert_equal expected, JSON.parse(@response.body)
  end

  test "using an unknown email" do
    get(
      "/api/v2/contacts/toot@tiit.com",
    )

    assert_response 404
  end
end

Voilà voilà. Des bisous à la moi du futur !


L’équipe Synbioz.
Libres d’être ensemble.