Lorsque l'on crée une application complexe il est important de tester son code afin de s'assurer que tout fonctionne comme attendu, et ce, à chaque étape du projet. Par défaut, Ruby on Rails utilise les tests la librairies MiniTest mais accepte d'autres frameworks de tests comme Rspec par exemple.
MiniTest ou Rspec ?
Concretement les 2 frameworks vont vous permettre de tester votre code, le choix de l'un ou de l'autre va plutôt dépendre de votre style.
MiniTest
# MiniTest
class PostsControllerTest < ActionDispatch::IntegrationTest
setup do
@valid_attrs = {
name: "Title",
content: "Lorem ipsum..."
}
end
test "should get index" do
get posts_url
assert_response :success
end
test "should create post" do
assert_difference('Post.count') do
post posts_url, params: { post: @valid_attrs }
end
assert_redirected_to post_url(Post.last)
end
end
Rspec
RSpec.describe PostsController, type: :controller do
let(:valid_attributes) {
{
name: "Title",
content: "Lorem ipsum..."
}
}
let(:post) {
Post.create! valid_attributes
}
describe "GET #index" do
it "assigns all posts as @posts" do
get :index, params: {}
expect(assigns(:posts)).to eq([post])
end
end
describe "POST #create" do
context "with valid params" do
before do
post :create, params: {post: valid_attributes}
end
it "assigns a newly created post as @post" do
expect(assigns(:post)).to be_a(Post)
expect(assigns(:post)).to be_persisted
expect(Post.count).to eq(1)
end
it "redirects to the created post" do
expect(response).to redirect_to(Post.last)
end
end
end
end
Rspec propose une syntaxe plus tournée vers le BDD (behaviour driven development) qui personnellement me convient un peu plus. Mais n'hésitez pas à tester les 2 méthodes avant de faire votre choix.
Rspec + Rails
Pour commencer à utiliser rspec avec Ruby on Rails il suffit d'ajouter la gem rspec-rails
à votre fichier Gemfile. Une fois installée il faut générer les fichier nécessaire à la bonne éxécution des tests :
rails g rspec:install
Cette commande permet de générer les fichiers spec_helper
et rails_helper
qui seront ensuite inclue dans tous vos tests. Et c'est tout ce qu'il y a à faire. Maintenant, lorsque vous générer un controller, un modèle ou n'importe quoi d'autre, les fichiers spec
seront automatiquement générés.
Il est aussi possible de générer des fichiers de spec directement avec le générateur
rspec:controller
rspec:feature
rspec:helper
rspec:install
rspec:integration
rspec:job
rspec:mailer
rspec:model
rspec:observer
rspec:request
rspec:scaffold
rspec:view
Afin d'apprendre le fonctionnement des tests de bases je vous conseille de générer un scaffold ce qui vous donnera un large éventail d'exemple. Ensuite, pour aller plus loin n'hésitez pas à regarder la documentation et le site BetterSpecs.org qui donne de très bon conseil concernant la manière d'écrire de bons tests avec Rspec.
Automatiser avec Guard
Lorsque l'on travail sur un projet on veut parfois relancer les tests lors de la modification d'un fichier. La gem guard-rspec permet de générer la configuration nécessaire au relancement automatique des tests. La gem s'installe depuis le gemfile :
gem 'guard-rspec', require: false
On génère ensuite la configuration guard à l'aide de la commande
bundle exec guard init rspec
Et hop ! Le tour est joué. Vous pouvez maintenant utiliser la commande guard
qui surveillera la modification de fichiers ruby et qui lancera les tests correspondants aux fichiers modifiés.
FactoryGirl, pour remplacer les fixtures
Pour certains tests on sera parfois ammener à travailler avec une base de données. Afin d'insérer des données de tests il est possible d'utiliser le système de fixtures de Rails. Malhereusement ce système est un peu rigide et devient rapidement complexe pour de large quantités de données. factory_girl
est une gem qui va permettre de générer des objets plus rapidement et plus simplement. Elle s'intègre très bien à Rails gràce à la gem factory_girl_rails
.
factory :user, aliases: [:author, :commenter] do
first_name "John"
last_name "Doe"
date_of_birth { 18.years.ago }
end
factory :post do
author
# instead of
# association :author, factory: :user
title "How to read a book effectively"
body "There are five steps involved."
end
Il est ensuite possible de générer l'objet de différente manière :
user = build(:user) # On retourne une simple instance
user = create(:user) # On retourne une instance persistée en base de données
attrs = attributes_for(:user) # On retourne un hash d'attributs
stub = build_stubbed(:user) # On retourne une instance avec les attributs stubbés