Tester son code avec Rspec

Résumé Support

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