2013-10-24 44 views
3

我想解决一个问题,我的rspec测试创建一个对象,但计数似乎并没有改变我的任何尝试。我确信我错过了一些非常基本的东西。Rspec不会改变创建

这里是我的RSpec:

before do 
    login_account_admin(user) 
    @group = Factory(:group, :code => "GR_111", :description => "description for GR_111") 
    Group.stub!(:find).and_return(@group) 
    end 

    describe "#create" do 

    it "should create a new group object" do 
     group_params = {:code => "NEW_GROUP", :description => "description for NEW_GROUP"} 
     expect { 
     post :create, :service_id => service, :cdb_group => group_params, :button => "save", :format => "js" 
     }.to change(Group, :count).by(1) 
    end 

    it "should not create a new group object with invalid code format" do 
     group_params = {:code => "invalid", :description => "description for invalid code name group"} 
     expect { 
     post :create, :service_id => service, :cdb_group => group_params, :button => "save", :format => "js" 
     }.to_not change(Group, :count) 
    end 

    end 

“代码” 参数只能包含大写字母A到Z,0-9和_

这里是#创建控制器方法定义

def create 
@group = Group.new(params[:cdb_group]) 
respond_to do |format| 
    if params[:button] == "cancel" 
    format.js { render "hide_new"} 
    elsif @group.save 
    format.js { 
     render 'show_new_group' 
    } 
    format.html { redirect_to(some_path(@service), :notice => 'Group was successfully created.') } 
    format.xml { head :ok } 
    end 
end 
end 

下面是组型号:

class Group < ActiveRecord::Base 

    validates_uniqueness_of :code 
    validates_presence_of :code, :description 
    validates_format_of :code, :without => /[^A-Z0-9_]/ , :message => 'can only contain uppercase letters A to Z, 0-9 and _' 
end 

每当我试图运行rspec的测试中,我得到以下错误: -

1) GroupsController User As Account Admin goes to #create should create a new group object 
Failure/Error: expect { 
    count should have been changed by 1, but was changed by 0 
# ./spec/controllers/groups_controller_spec.rb:51 

2) GroupsController User As Account Admin goes to #create should not create a new group object with invalid code format 
Failure/Error: expect { 
    count should not have changed, but did change from 2 to 1 
# ./spec/controllers/groups_controller_spec.rb:58 

在这方面的任何帮助,将不胜感激?

+0

需要更多的细节。 Group模型的外观如何。它是否有验证失败。你确定你的测试没有正常工作,你的代码实际上是错误的,测试指出了这一点? – cpjolicoeur

+0

我敢打赌,你可以在阅读本文后自行解决它:http://nofail.de/2013/10/debugging-rails-applications-in-development/另一个提示,总是实现'else'部分 – phoet

+0

Hi @cpjolicoeur :我已经更新了上面的问题,以表明团队模型如何。是的,代码实际上是正确的,因为它已经通过浏览器成功测试过了,我不会遇到任何错误。 实现了else部分。为了简洁起见,我没有把它列入上面。 – aliibrahim

回答

5

每当我们的测试给我们带来意想不到的麻烦时,重要的是退后一步并重新评估我们的方法。通常,这表示一些设计问题,无论是用我们正在测试的代码还是用测试本身。

尽管听起来像使用截断策略已经解决了这个特殊问题(请参阅下面的更多内容),但我建议还有更多要了解情况。

考虑上述规范中的两个示例。它们之间唯一的区别在于code参数是否有效。我会争辩说,这些例子实际上是测试 模型,而不是控制器

现在,如果我们对我们的模型测试覆盖有信心,那么我们可以采取不同的方法来控制器规格。从控制器的角度来看,该模型是一个协作者而且一般情况下,我们总是希望避免间接测试协作者。在这种情况下,我们可以使用模拟来模拟Group模型的行为,并仅隔离测试控制器行为。

像这样(请注意下面的代码是不完整的,未经测试):

# spec/controllers/groups_controller_spec.rb 
describe "#create" do 

    before do 
    # use a Test Double instead of a real model 
    @new_group = double(Group) 
    @params = { :cdb_group => 'stub_cdb_group_param', :service_id => service } 
    # using should_receive ensures the controller calls new correctly 
    Group.should_receive(:new).with(@params[:cdb_group]).and_return(@new_group) 
    end 

    context "when cancelled responding to js" do 
    it "renders hide_new" do 
     post :create, @params.merge({:button => "cancel", :format => "js"}) 
     expect(response).to render_template('hide_new') 
    end 
    end 

    context "with valid params" do 
    before do 
     @new_group.should_receive(:save).and_return(true) 
    end 

    context "responding to json" # ... 

    context "responding to html" # ... 

    context "responding to xml" #... 
    end 

    context "with invalid params" do 
    before do 
     @new_group.should_receive(:save).and_return(false) 
    end 

    # ... 
    end 

end 

虽然上面没有专门与记录数你有解决这个问题,我怀疑问题可能消失一旦你正确地分离你的测试目标。

如果您选择坚持使用数据库截断,请考虑使用它,如here所述。

我希望至少有一些帮助:)。

+0

这是对已编写的测试的一些极好的反馈。事实上,他们正在测试模型,而不是控制器本身。 – aliibrahim

0

您应该测试...

1)Group.create(group_params).should be_truegroup_params = ...

如果失败,可能与问题建模或测试环境。后post ...

2)response.status.should == 302如果失败,可能与会议(认证/授权问题)。

3)assigns(:group).should be_validpost ...

如果失败,该问题可能与控制器。

+0

我测试了上述3种情况,并没有在其中任何一种情况下失败。 – aliibrahim

+1

hmm ...期待{Group.create(group_params)} .to改变(Group,:count).by(1)'? – labocho

+0

这一个实际通过。 我认为它必须做一些我的spec_helper.rb文件?如果我在代码中进行调试,在前面块(通过Factory)中创建的@group对象确实出现(通过检查Group.all.inspect),但在post:group之后...当我检查Group.all.inspect只有第二个创建的对象出现。因此,计数不会改变1,并且保持不变。这里是我的spec_helper.rb文件的链接(https://gist.github.com/aliibrahim/7152042)。对此有何想法?感谢您的时间到目前为止! – aliibrahim

1

摆弄我的spec_helper.rb文件后。事实证明,我必须将我的数据库清理策略改为截断。这里是我的spec_helper文件,以供参考(https://gist.github.com/aliibrahim/7152042

我在我的代码和禁用transactional_fixtures

config.use_transactional_fixtures = false 

的改变了这一行,现在我的数据库清理策略是:

config.before(:suite) do 
    DatabaseCleaner.strategy = :truncation 
    DatabaseCleaner.clean_with(:truncation) 
    end 

这在每个场景的开始/结束之前给出一个清晰的数据库。希望这有助于任何人!

+0

这是正确的答案。除非我设置'config.use_transactional_fixtures = false',否则'assert_difference'永远不会通过。 – RajaRaviVarma