2014-01-24 53 views
1

我遇到问题测试一个相当简单的事情,即在数据库中不允许的代码的重复性。跳过before_validation上::在测试中创建

比方说,我有这样的模式:

class Ticket < ActiveRecord::Base 
    attr_accessible :code, :series, :sec_code 
    validates_uniqueness_of :code, scope:[:series,:sec_code] 

    before_validation :generate_codes, on: :create 


    private 
    def generate_codes 
    self.code=rand.to_s[2..9] #-> 8 digit code 
    self.sec_code=rand.to_s[2..4] #-> 2 digit security code 
    self.series=('A'..'Z').to_a.sample #-> one character series 
    end 

end 

然后我想测试的唯一性验证起作用,以这样的方式

require 'spec_helper' 

describe Ticket do 
    before do 
    @ticket=Ticket.create 
    end 
    subject{@ticket} 

    it{ should respond_to(:code)} 
    ... 

    describe ", duplicate codes" do 
    before do 
     [email protected] 
     #Here lays the problem since this calls `generate_codes` 
     #before saving, so it ends up not being a duplicate! 
     dup_ticket.save #<--- 
    end 
    it{ should_not be_valid} 
    end 

end 

我正在考虑使用after_initialize,但是每当对象被实例化时,即在从DB中提取之后,这就被调用,这是不期望的。 我想知道为什么generate_codes即使在过滤器回调中有on: :create也被调用?

回答

0

通过jklina的答案/评论的启发,我发现使用update_attribute在这种情况下帮助,并没有确认回调之前触发我可以更新的领域。 所以测试变为:

require 'spec_helper' 

describe Ticket do 
    before do 
    @ticket=Ticket.create 
    end 
    subject{@ticket} 

    it{ should respond_to(:code)} 
    ... 

    describe ", duplicate codes" do 
    before do 
     [email protected] 
     dup_ticket.update_attribute(:code, @ticket.code) 
     dup_ticket.update_attribute(:sec_code, @ticket.sec_code) 
     dup_ticket.update_attribute(:series, @ticket.series) 
    end 
    it{ should_not be_valid} 
    end 

end 

因此反映codesec_code,并series在ActiveRecord的表相同的值。测试做到了预期的效果。

0

你可以尝试存根generate_codes方法来返回你想要的。因此,也许补充说:

allow(dup_ticket).to receive(:generate_codes).and_return(nil)

我不能对此进行测试,但是这可能会阻止记录从产生新的价值。我并不完全熟悉dup,因此您需要确保dup也带有代码值。

+0

我会尽力的,谢谢!尽管如果可能的话,我会*尽量避免嘲笑和剔除tbh。 :/ – lllllll

+1

由于所有的代码似乎都可以访问,所以可以使用'dup_ticket.update_attributes(代码:@ ticket.code ...)'。这会保存记录并且不运行generate_codes命令,因为你似乎只在'create'上创建了它' – jklina

+0

我也考虑过这个问题,但是我认为'save'会被调用,并且它确实没有帮助。然而!如果我使用'update_attribute'来代替回调,那么回调并不是“执行”的,这在最后还是有效的! – lllllll