需要帮助Rspec测试

时间:2011-11-01 00:14:36

标签: ruby-on-rails-3 rspec rspec2 rspec-rails

我正在尝试学习RSpec并为CRUD操作编写测试。这是我的控制器:

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 UPDATE测试失败时运行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

1 个答案:

答案 0 :(得分:2)

这就是事情。

当你正在进行存根时,你只是说“如果调用此方法链,则返回此状态。”这有两个问题。 1)代码不会调用build,2)没有实际的关联。

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

有关详细信息,请参阅this SO postthis SO post。常规数组不会像{AR}方法那样处理find方法,也不会返回单个文章。

由于你拥有文章ID,你可能只返回该特定文章,但你的目标是从用户的文章中返回该文章,以避免更新其他人的文章(我假设)。

This SO post也可以提供帮助,this

换句话说,你可能想要一个真实的用户,有真正的关联对象,所以像find这样的东西可以不用hackery。

(我完全认识到这不是一个真正的答案;我从来没有通过存根,我使用工厂/等来做到这一点。)