Test d'un module avec rspec


#1

Bonjour à tous,

Voila j’utilise un module pour gérer des sous domaines, placé dans le
dossier lib/ qui me retourne une instance particulière d’un modele
selon le sous sous-domaine. Ce module placé dans application.rb est
utilisable par tous les controleurs. Ceci me sert à scoper les autres
données liées à cet instance. Mon problème est que je n’arrive pas à
le tester avec rspec dans le contexte d’un sous domaine justement. Par
ailleurs j’ai dans application.rb un before_filter qui teste la
validité du sous-domaine demandé

Voici le module :

Inspired by

http://dev.rubyonrails.org/svn/rails/plugins/account_location/lib/account_location.rb

module SubdomainTeams
def self.included( controller )
if controller.respond_to? :helper_method
controller.helper_method
(:team_domain, :team_subdomain, :team_url,
:current_team,:default_team_subdomain, :default_team_url)
end
end

protected

TODO: need to handle www as well

def default_team_subdomain
‘’ # ‘www’ || ‘’
end

def team_url( team_subdomain = default_team_subdomain, use_ssl =
request.ssl? )
http_protocol(use_ssl) + team_host(team_subdomain)
end

def team_host( subdomain )
team_host = ‘’
team_host << subdomain + ‘.’
team_host << team_domain
end

def team_domain
team_domain = ‘’
team_domain << request.domain + request.port_string
end

def team_subdomain
request.subdomains.first || ‘’
end

def default_team_url( use_ssl = request.ssl? )
http_protocol(use_ssl) + team_domain
end

def current_team
Team.find_by_subdomain(team_subdomain)
end

def http_protocol( use_ssl = request.ssl? )
(use_ssl ? “https://” : “http://”)
end
end

et voici un un contrôleur l’utilisant :

class PostsController < ApplicationController
before_filter :find_team

def index
if current_team
@posts = current_team.posts.of_the_week
elsif @team
@posts = @team.posts.of_the_week
end
end

Le before_filter est :

before_filter :check_team_status

def check_team_status
unless team_subdomain == default_team_subdomain
# TODO : check if the team has a valid subscription
if !current_team.nil? && current_team.valid_subscription == true
return true
end
redirect_to default_team_url if current_team.nil?
end
end

Comment faire pour tester l’action index du controleur Posts ds le
contexte d’un sous-domaine ? C’est à dire avec la variable
current_team à non nil ?

Merci d’avance.

Gilles.


#2

Gilles a écrit :

end
http_protocol(use_ssl) + team_host(team_subdomain)
team_domain << request.domain + request.port_string
def current_team
class PostsController < ApplicationController

 redirect_to default_team_url if current_team.nil?

end
end

Comment faire pour tester l’action index du controleur Posts ds le
contexte d’un sous-domaine ? C’est à dire avec la variable
current_team à non nil ?

describe PostsController do
before(:each) do
@controller.stub!(:domain).and_return(‘my_domain’)
@controller.stub!(:port_string).and_return(‘80’)
@controller.stub!(:subdomains).and_return([‘my_first_subdomain’,
‘next’, ‘othernext’]
end
end

un truc comme ca devrait être une piste.


Cyril M.
http://blog.shingara.fr


#3

ou bien un truc comme ça devrais le faire (je crois que c’est le
referer qui est utilisé, sinon faut setter la bonne clé)

before(:each) do
@request.env[‘HTTP_REFERER’] = ‘subdomain.domain.com
end


http://xilinus.com Web Application Development, Consulting, Training
http://mapeed.com Markers fusion plugin for your online maps


#4

Oups ! j’ai parlé trop vite …
Les specs échouent toujours … dommage, je ne comprends pas encore ce
qui se passe …
les @controller.stub! n’ont pas l’air d’apporter quelquechose …


#5

Merci du coup de main, j’ai intégré ces quelques lignes et mes specs
passent maintenant. Mais je ne comprends pas entièrement ce qui se
passe … c’est frustrant …


#6

Hello,

ce que je fais d’habitude:

  • une première série de tests portant sur le before filter (vérifier
    qu’il fonctionne, empêche les gens sans souscription de rentrer,
    laisse passer ceux qui en ont une…)
  • une deuxième série de tests portant sur la fonctionnalité elle-même,
    en supposant que le before filter est passé

Ça revient à appliquer la “separation of concerns” comme ils disent
dans les livres anglais.

Là j’ai l’impression que tu cherches plutôt à réaliser la deuxième
série de tests. Dans ce cas je te conseille de “stubber plus haut”.
Peut-être que quelque chose comme suit te conviendrait (c’est ce que
j’ai tendance à faire):

before(:each) do
controller.stub!(:find_team).and_return(true)
controller.stub!(:current_team).and_return(my_mock_team)
end

à côté de ça j’ai généralement une spec qui se concentre sur le
before_filter (1ère série de tests). Ex ici, où le before filter fait
un Customer.find_by_access_token pour authentifier le client:

describe CustomersController, “authentication” do

before(:each) do
controller.use_rails_error_handling!
end

it “denies access if a valid access token hasn’t been provided” do
Customer.should_receive(:find_by_access_token).with(“wrong-
token”).and_return(nil)
get :index, :access_token => “wrong-token”
response.response_code.should eql(403)
session[:customer].should be_nil
end

it “grants access if a valid access token has been provided” do
customer = mock(“customer”, :id => 44)
Customer.should_receive(:find_by_access_token).with(“good-
token”).and_return(customer)
get :index, :access_token => “good-token”
response.should be_success
session[:customer].should == 44
end

end

voilà j’espère que ça t’aidera dans ta quête de la “spec qui va bien”.

Thibaut

http://learnivore.com
http://blog.logeek.fr


#7

hé bien après quelques investigations, c’est toujours l’impasse en
quelque sorte. je réussie à faire passer les specs mais sans utiliser
aucune des suggestions, mais tous simplement en affectant la variable
@current_team à un fixture ds le bef…each

context "without a team_id but a current_team by subdomain" do

  fixtures :teams

  before(:each) do
    # @controller.stub!(:domain).and_return('basketballstat.dev')
    # @controller.stub!(:port_string).and_return('80')
    # @controller.stub!(:subdomains).and_return(['myteam',
    #       'next', 'othernext'])
    # @request.env['HTTP_REFERER'] = 'myteam.basketballstat.dev:

3000’
@current_team = teams(‘myteam’)
@posts_proxy = mock(‘posts’)
@post = mock_model(Post)
end

  def do_get
    get :show, :id => "1"
  end

  it "should find the requested current_team's post and assigns it

to the show view" do
@current_team.should_receive(:posts).and_return(@posts_proxy)
@posts_proxy.should_receive(:find).with(“1”).and_return(@post)
do_get
assigns[:post].should equal(@post)
response.should render_template(‘show’)
end

end

#8

Merci,

Cela a fonctionné. rSpec comporte des subtilités qui poussent à mieux
comprendre ce que l’on code et c’est tout l’intérêt. Ce n’est pas
toujours évident mais on ce sent mieux après avoir compris, alors
merci pour ces explications claires, j’ai encore un peu progressé
grace à toi.

Gilles.