Ruby on Rails, TDD et développement en top-down
Vous avez entendu parler du TDD, vous souhaiteriez l’appliquer mais il faut un début à tout.
Par où commencer ? Quel process suivre quand on développe une application rails ?
Voyons donc ce que le bon vieux “rails generate controller” nous mâche comme travail ou plutôt, comment maîtriser le processus de génération.
Je vous propose de réaliser en TDD l’équivalent de cette commande pour réaliser l’objectif suivant: “Je souhaite avoir une page affichant une liste d’événements”
Et comme il faut bien commencer, commençons par un bon…
rails new
“J’ai donc besoin d’une page contenant la liste des événements”
Test d’acceptation: Si je tape l’url de ma liste dans mon navigateur, je devrais voir quelquechose. Test Browser: En allant à cette URL, j’obtiens une page d’erreur 404 !
Il s’agit d’une de liste d’événements et c’est tout ce dont j’aurai besoin. Nous aurons donc en premier lieu besoin d’une URL, d’une route pour afficher notre résultat.
match ‘events/index’ => ‘events#index’, :via => :get
Créons donc la vue qui accueillera cette liste, le controller associé et bien évidemment, le fichier de test de ce controller. Fichiers crées:
app/views/events/index.html.erb
app/controllers/events_controller.rb
spec/controllers/events_controller_spec.rb
Dans un premier temps, remplissons notre vue d’événements fakes.
Event 1
Event 2
…
Event n
Pour que mon test d’acceptation soit complet, notre premier test devra donc vérifier que mon URL réponde.
describe EventController do
describe 'get index' do
it 'works' do
get :index
response.should be_success
end
end
Rake spec: NoMethodError, indeed !
Test Browser: En allant à cette URL, j’obtiens toujours une page d’erreur 404 !
Codons donc la fonctionnalité:
class EventController < ApplicationController
def index
end
end
Rake spec
: Tout est vert !
Test Browser: En allant à cette URL, j’obtiens une page… blanche !
Félicitations, non seulement vous avez remplis le premier test d’acceptation mais en plus, vous venez d’entrer dans la boucle du TDD ! La suite se déroulera exactement de la même façons, par une route top-down que l’on peut synthétiser en ces étapes:
- écriture de la vue;
- test navigateur;
- écriture du test;
- écriture du code.
Comme nous allons le voir par la suite, ces étapes sont répétées n fois jusqu’à ce que l’on atteigne notre objectif principal.
“Je voudrais plutôt avoir une liste d’événements venant de ma base”
Test d’acceptation: Si je vais sur la page de liste d’events, je devrais pouvoir voir des événements venant de ma base de données.
Je modifie ainsi ma vue avec ce que je souhaiterais avoir.
index.html.erb
<%- @myevents.each do |party| %>
<%= party.title %>
<% end %>
Test Browser: Gros plantage de rails, WTF is going on ?!
“Je dois régler cette erreur !”
Créons un test adapté à notre problème. Selon notre vue, nous voudrions quelquechose qui itère et présente une liste d’événements. La structure la plus adaptée est donc le tableau. Testons donc que j’ai un tableau !
event_controller_spec.rb
it 'shows an empty list when no event is available' do
get :index
assigns(:bouquins).should be_eql([])
end
Test Browser: J’ai maintenant une page vide ne contenant aucun évent.
“OK, mais je n’ai toujours rien, donne moi un Event !”
spec/controllers/event_controller_spec.rb
it 'shows an event when only one event available' do
events = [OpenStruct.new]
Event.should_receive(:all).and_return(events)
get :index
assigns(:myevents).should be_eql(events)
end
Le test précédent suggérait que j’appelle une méthode :all depuis mon modèle Event.
Ecrivons donc le test qui répond à la problématique dans un ficheir de test du présupposé modèle.
spec/models/event_spec.rb
describe '#all' do
it "returns an empty array when no event" do
Event.all.should be_eql([])
end
end
Rake spec
: D’où vient ce modèle Event ? Et cette méthode :all, dude ?!
Nous avons besoin d’un modèle Event ? Nous devons donc créer le modèle et son test associé. Passons ici par une migration:
rails generate model Event title:string
Cette dernière commande nous remplira là un modèle à notre place et un fichier de migration associé
model/event.rb
class Event < ActiveRecord::Base
end
Rake spec
: Vert pour mon test de modèle mais toujours rouge pour mon test de controller.
ActiveRecord possède déjà une méthode :all récupérant tous les records du modèle correspondant.
Afin de corriger notre test de controller, ajoutons le code qui le fera passer au vert.
event_controller.rb
def index
@myevents = Event.all
end
Rake spec
: GREAT AND GREEN !
Créons un jeu de test directement en console
rails console
event = Event.new
event.title = “Réunion d’anciens”
event.save
event = Event.new
event.title = “Pétanque sur la place des fêtes”
event.save
Test browser: Hooray! J’ai mes deux événements qui s’affichent à l’écran. La boucle est ainsi bouclée.