Comment tester devise ? réélement ?

Alors que j'ai cherché comment tester facilement Devise. J'ai indiqué une technique dans mon précédent post. Mais cette technique est loin d'être la meilleure. Voici donc la nouvelle solution, la solution officielle.

Il suffit d'inclure Devise::TestHelpers. Ensuite pour se logger avec un utilisateur, on utilise la méthode sign_in. La méthode sign_out existe aussi.

[...]
Published on Lun 30 nov 2009 21:58
0 commentaires

Devise ? c'est bien, mais il faut le tester.

Alors que j'ai évoqué ma migration de Merb à Rails pour Oupsnow, il a fallu trouver un système d'authentification ORM Agnostique.

Le plugin d'authentification le plus connu à l'heure actuel est Authlogic. Ce plugin est vraiment très performant, mais tous les essais de le rendre ORM Agnostique ont été vain. C'est alors qu'au même moment, durant le Rails Summit 2009, George Guimarães et Carlos Antonio annoncent la sortie de Devise, un plugin Rails au dessus de Warden ( Rack middleware d'authentification). C'est exactement, ce qu'il me faut, un nouveau système d'authentification a tester et peut-être une possibilité d'ajouter une couche d'ORM Agnostique dedans. En plus Warden étant un RackMiddleware, je pourrais un peu tester ce que ça donne.

J'installe donc Devise et commence à l'utiliser dans Oupsnow. Tout se passe à merveille, jusqu'au moment où il faut faire les tests. Tout de suite le bât blesse. Les tests controlleurs de Rails ne communiquent pas avec la couche Rack qui n'est pas initialisée. On se retrouve donc avec une impossibilité de définir si un utilisateur est loggé ou non et si oui, qui est cet utilisateur.

Après de nombreux tests et essais. J'ai fini par trouver comment faire. Warden ajoute à la requête une variable d'environment dans la requête. On peux y accéder par request.env['warden']. Il suffit donc de remplir cette variable.

Pour avoir un utilisateur non loggé, il faut faire :

def unlogged
  request.env['warden'] = Warden::Proxy.new(request.env, {:default_strategies => [:rememberable, :authenticable],:silence_missing_strategies => true})
end

Pour se logger avec un utilisateur en particulier il faut faire :

def logged_as(user)
  proxy = Warden::Proxy.new(request.env, {:default_strategies => [:rememberable, :authenticable], :silence_missing_strategies => true})
  proxy.set_user(user, :store => true, :scope => :user)
  request.env['warden'] = proxy
end

Personnellement, j'aime beaucoup devise. A tel point que j'ai permis de le rendre ORM Agnostique et compatible avec MongoMapper.

EDIT du 30 Novembre 2009: la technique indiquée ici n'est pas optimum et ne marche pas avec les dernières versions de Devise. utilisez plutôt la technique décrite dans mon ticket Comment tester devise ? réélement ?

[...]
Published on Jeu 19 nov 2009 22:36
0 commentaires

Pourquoi Rspec au lieu de Test::Unit?

Dernièrement, on m'a posé la question toute bête :

Pourquoi Rspec au lieu de Test::Unit ?

C'est vrai que je suis un adepte de Rspec et que je n'utilise que ça si c'est possible. mais je n'ai jamais expliqué ici clairement ce qui me pousse dans ce choix. Donc voici un résumé très bref de mon choix.

Les formateurs

Une des options méconnues de Rspec est la possibilité de définir son formateur. Il existe ainsi plusieurs formateurs base. On peux ainsi avoir un retour direct sous format HTML ou text avec les points ( classique avec Test::Unit). Mais certain formateur peuvent aussi calculer le temps que dure un exemple. Ainsi nous avons une facilité de détection des test les plus lent pour les refactorer et essayer d'améliorer le temps de réalisation de ses tests. Dans ce sens, j'ai moi même créer mon propre formateur Rspec.

Les tests partagés

Rspec dispose d'une possibilité sous estimés, les tests partagés. En effet, on peux définir certain jeux de test comme "partageable" on a ainsi la possibilité de les incorporer facilement dans divers tests. C'est une fonction vraiment pratique dans le cadre de test fonctionnel principalement. Plus besoin de copier/coller son code. :)

Compatibilité Test::Unit

Le passage a Rspec est assez aisé de part sa compatibilité avec Test::Unit. En effet, si vous n'êtes pas familier ou que vous n'aimez pas la formalation my_array.should be_empty, rien ne vous y oblige. Vous pouvez tout à fait utiliser la syntaxe Test::Unit assert my_array.empty?. La migration s'en trouve très largement aisée.

[...]
Published on Dim 04 oct 2009 20:59
2 commentaires

Et si on écrivait une histoire à Rails ?

Sous ce titre particulier, je voudrais parler un peu des stories de Rspec. En effet, depuis la version 1.0 de RSpec, les stories ont été ajouté à Rspec. Ce système de story peux tout à fait être utilisé au sein de Rails pour permettre de créer des test d'intégrations. En effet, avec les spec traditionnels, nous ne pouvons pas réellement réaliser de test d'intégration. Avec les story nous pouvons le faire très facilement, que ca soit lisible et surtout très facilement répétable et modifiable. Mais le mieux est de vous montrer comment l'intégrer et l'utiliser à Rails.

Si vous avez installer Rspec pour Rails et lancé la génération de rspec alors vous devez avoir dans votre arborescence un dossier stories. C'est en général dans ce dossier que nous mettons les stories.

Votre première histoire

Nous allons supposer que vous avez un petit système de login et que vous voulez le tester. Il suffit de créer le fichier login_story.rb comme ci-dessous

login_story.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Story "Un Utilisateur s'authentifie", %{
  Je suis un utilisateur et je veux m'authentifier
  Alors j'y arrive
}, :type => RailsStory do
  
  Scenario "Logged successful" do
    Given "un login", "shingara" do |login|
      @login = login
    end
    
    And "un mot de passe", "mon_password" do |password|
      @password = password
    end
    
    And "l'utilisateur est creer" do
      User.create {:login => @login, :password => @password}
    end
    
    When "je vais sur", "/" do |page|
      get page
    end
    
    Then "je suis redirige vers la page de login" do
      response.should redirect_to '/login"
      follow_redirect!
    end

   When "Je me log" do
     post "/login", :login => @login, :password => @password
   end

   Then "Je suis redirige vers ", "/" do |path|
      response.should redirect_to ("/")
      follow_redirect!
   end
  end

Voici donc un test de story avec Rails. Il faut bien penser à utiliser le type RailsStory pour que Story soit un Objet qui hérite de ActionController::IntegrationTest et puisse ainsi avoir toutes les méthodes utilent comme le follow_redirect!. Par contre, il faut faire attention, car le load des fixtures n'existent pas dans les Story, il faut créer soit-même un étape qui le fasse pour que cela soit possible.

Et en plus répétable ?

Maintenant une autre grande fonctionnalité des Story de Rspec est la possibilité de faire des stories en plain-text. Ainsi notre story précédente deviendrait tout simplement :

login_story.rb
Story: Un Utilisateur s'authentifie Je suis un utilisateur et je veux m'authentifier Alors j'y arrive Scenario: Logged successful Given un login shingara And un mot de passe mon_password And l'utilisateur est creer When je vais sur / Then je suis redirige vers la page de login When Je me log Then Je suis redirige vers /

A ce moment là plus besoin d'être développeur pour comprendre ce que fait le test. Pour cela en fait il faut créer toute une batterie de jeu d'étapes. Les étapes sont de 3 Types :

  • Given : qui sont les données de base ou postulat
  • When : qui sont les actions
  • Then : qui sont les résultats

Il suffit donc de créer un fichier d'étapes qui comprenne toutes les étapes indiqués dans le fichier texte :

login_steps.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
steps_for(:gallery) do

    Given "un login $login" do |login|
      @login = login
    end
    
    And "un mot de passe $password" do |password|
      @password = password
    end
    
    And "l'utilisateur est creer" do
      User.create {:login => @login, :password => @password}
    end
    
    When "je vais sur $page do |page|
      get page
    end
    
    Then "je suis redirige vers la page de login" do
      response.should redirect_to '/login"
      follow_redirect!
    end

   When "Je me log" do
     post "/login", :login => @login, :password => @password
   end

   Then "Je suis redirige vers  $path" do |path|
      response.should redirect_to ("/")
      follow_redirect!
   end
end

En indiquant que le fichier texte prend appui sur ce fichier d'étape, Rspec fait tout le reste. On appelle notre test de la façon suivante :

all.rb
1
2
3
4
5
require File.join(File.dirname(__FILE__), *%w[helper])

with_steps_for(:login) do
  run File.join(File.dirname(__FILE__), "login_story", :type => RailsStory
end

Ce qui est vraiment génial dans tout ça c'est la possibilité du coup de changer l'ordre des étapes voir de leur paramètres. Ainsi le test suivant peux être réalisé sans nouveau code ruby d'ajouté :

login_story.rb
Story: Un Utilisateur s'authentifie Je suis un utilisateur et je veux m'authentifier Alors j'y arrive Scenario: Logged successful Given un login shingara And un mot de passe mon_password And l'utilisateur est creer When je vais sur / Then je suis redirige vers la page de login When Je me log Then Je suis redirige vers / Scenario: Je vais directement sur la page de login et j'y reste Given un login shingara And un mot de passe mon_password And l'utilisateur est creer When je vais sur /login And Je me log Then Je suis redirige vers /login
[...]
Published on Jeu 03 avr 2008 20:29
0 commentaires

RSS Follow me on Twitter