2011-11-01 119 views
0

我在学习RSpec并为CRUD操作编写测试。这里是我的控制器:需要帮助Rspec测试

class ArticlesController < ApplicationController 

    respond_to :html, :json 

    before_filter :authenticate_user! 

    # GET /articles 
    # GET /articles.json 
    def index 
    @articles = current_user.articles.all 
    respond_with(@articles) 
    end 

    # GET /articles/1 
    # GET /articles/1.json 
    def show 
    @article = current_user.articles.find(params[:id]) 
    respond_with @article 
    end 

    # GET /articles/new 
    # GET /articles/new.json 
    def new 
    @article = current_user.articles.build 
    respond_with @article 
    end 

    # GET /articles/1/edit 
    def edit 
    @article = get_article(params[:id]) 
    end 

    # POST /articles 
    # POST /articles.json 
    def create 
    @article = current_user.articles.build(params[:article]) 
    flash[:notice] = "Article was successfully created!" if @article.save 
    respond_with(@article, location: articles_path) 
    end 

    # PUT /articles/1 
    # PUT /articles/1.json 
    def update 
    @article = get_article(params[:id]) 
    if @article.update_attributes(params[:article]) 
     flash[:notice] = "Article was successfully updated." 
    end 
    respond_with @article 
    end 

    # DELETE /articles/1 
    # DELETE /articles/1.json 
    def destroy 
    @article = get_article(params[:id]) 
    @article.destroy 
    respond_with @article 
    end 

    private 
    def get_article(article_id) 
    current_user.articles.find(article_id) 
    end 
end 

而我的文章rspec的:

describe ArticlesController do 

    def valid_attributes 
    { 
     :title => "Introducting Node.js", 
     :content => "Node.js is an event-driven...." 
    } 
    end 

    let(:article) do 
    build(:article, valid_attributes) 
    end 

    describe "PUT 'update'" do 

    before(:each) do 
     controller.stub_chain(:current_user, :articles, :build) { article } 
    end 

    context "success" do 
     before(:each) do 
     article.should_receive(:update_attributes).and_return(true) 
     put :update, id: article.id 
     end 

     it "sets notice" do 
     flash[:notice].should eq("Article was successfully updated!") 
     end 
    end 
    end 

    describe "POST 'create'" do 

    before(:each) do 
     controller.stub_chain(:current_user, :articles, :build) { article } 
    end 

    context "success" do 
     before(:each) do 
     article.should_receive(:save).and_return(true) 
     post :create 
     end 

     it "sets notice" do 
     flash[:notice].should eq("Article was successfully created!") 
     end 

     it "should redirect to article path" do 
     response.should redirect_to(articles_path) 
     end 
    end 

    context "failure" do 
     before(:each) do 
     article.should_receive(:save).and_return(false).as_null_object 
     post :create 
     end 

     it "assigns @article" do 
     assigns(:article).should == article 
     end 
    end 
    end 
end 

我的问题是,当我运行PUT更新测试RSpec的失败。但POST测试已通过。我不知道发生了什么事。我正在使用带有omniauth的Rails 3.1.1。我没有使用Devise。这是测试结果。为什么?请帮帮我吗?

Failures: 

    1) ArticlesController PUT 'update' success sets notice 
    Failure/Error: put :update, id: article.id 
    NoMethodError: 
     undefined method `find' for #<Object:0xa3cfd20> 
    # ./app/controllers/articles_controller.rb:61:in `get_article' 
    # ./app/controllers/articles_controller.rb:44:in `update' 
    # ./spec/controllers/articles_controller_spec.rb:46:in `block (4 levels) in <top (required)>' 

Finished in 24.09 seconds 
5 examples, 1 failure 
+0

它看起来像你没有Article模型。 – megas

+0

我有一个文章模型。任何想法? – Zeck

+0

当我登录get_article函数的current_user.articles类类型为Object时。这是对的吗? – Zeck

回答

2

这是事情。

当你存根时,你只是说“如果这个方法链被调用,返回这个。”这有两个问题。 1)代码永远不会调用build,并且2)没有实际的关联。

我相信你需要存根current_user.articles才能返回文章集合。问题是AR关联不是实际的数组,而是代理。

有关更多详细信息,请参见this SO postthis SO post。常规数组不会将find方法看作是真正的AR方法,并且您不会返回单个文章。

既然你文章ID,您可以只是返回特定的文章,但你的目标是从用户的文章中返回的文章,以避免更新别人的(我认为)。

This SO post也可能有帮助,和this

换句话说,你可能想要一个真正的用户,并有真正的关联对象,所以诸如find之类的东西将不会工作。

(我充分认识到这不是一个真正的答案,我从来没有通过磕碰这样做,我用工厂的/ etc。)