我正在尝试学习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
答案 0 :(得分:2)
这就是事情。
当你正在进行存根时,你只是说“如果调用此方法链,则返回此状态。”这有两个问题。 1)代码不会调用build
,2)没有实际的关联。
我相信您需要存根current_user.articles
才能返回文章集。问题是AR关联不是实际的数组,它们是代理。
有关详细信息,请参阅this SO post和this SO post。常规数组不会像{AR}方法那样处理find
方法,也不会返回单个文章。
由于你拥有文章ID,你可能只返回该特定文章,但你的目标是从用户的文章中返回该文章,以避免更新其他人的文章(我假设)。
This SO post也可以提供帮助,this。
换句话说,你可能想要一个真实的用户,有真正的关联对象,所以像find
这样的东西可以不用hackery。
(我完全认识到这不是一个真正的答案;我从来没有通过存根,我使用工厂/等来做到这一点。)