2012-08-10 114 views
2

我有一个模型PromoCode具有.generate!方法,调用.generate产生使用SecureRandom.hex(5)字符串,并将其保存到数据库中:如何测试优惠券/促销代码的唯一性?

class PromoCode < ActiveRecord::Base 
    class << self 
    def generate 
     SecureRandom.hex 5 
    end 

    def generate! 
     return create! code: generate 
    end 
    end 
end 

现在我想写测试所产生的独特性规范串。只要生成不存在的PromoCode,就应该调用.generate方法。

我不知道如何做到这一点,因为我无法真正地将.generate方法剔除以返回固定值(因为那样它会卡在无限循环中)。

这是通过规格为模型到目前为止:

describe PromoCode do 
    describe ".generate" do 
    it "should return a string with a length of 10" do 
     code = PromoCode.generate 
     code.should be_a String 
     code.length.should eql 10 
    end 
    end 

    describe ".generate!" do 
    it "generates and returns a promocode" do 
     expect { 
     @promo = PromoCode.generate! 
     }.to change { PromoCode.count }.from(0).to(1) 

     @promo.code.should_not be_nil 
     @promo.code.length.should eql 10 
    end 

    it "generates a uniq promocode" do 
    end 
    end 
end 

理解的任何指示。

回答

3

Rspec的的and_return方法允许你指定将通过

中循环多次返回值例如,你可以写

PromoCode.stub(:generate).and_return('badcode1', 'badcode2', 'goodcode') 

这将导致第一次调用生成返回“badcode1”时,第二个'badcode2'等等......然后你可以检查返回的promocode是否使用了正确的代码。

如果你想成为你会想要一个数据库唯一约束比赛条件证明的,所以你的代码也许真的要成为

def generate! 
    create!(...) 
rescue ActiveRecord::RecordNotUnique 
    retry 
end 

在你的天赋,你会存根创造!方法提高第一次,但第二次返回值

+0

哇,不知道这件事,而且实现甚至比我有更多的优雅介意(使用循环和find_by_code)。非常感谢! – 2012-08-10 13:29:38

0

如果您将promocode保存在数据库中,您将在模型中为uniq promocode添加验证。所以你也可以在rspec中测试它。

这样,

it { should validate_uniqueness_of(:promocode) } 
3

又是怎么回事是这样的:创建一个PromoCode,保存结果,并尝试创建一个新的PromoCode与以前PromoCode对象code

it "should reject duplicate promocode" do 
    @promo = PromoCode.generate! 
    duplicate_promo = PromoCode.new(:code => @promo.code) 
    duplicate_promo.should_not be_valid 
end 

此外,这是模型级别,我假设你有一个在数据库中的密钥,将节省您的竞赛条件...

+0

我需要确保'generate!'生成一个代码 - 无论如何,直到一个唯一的代码已经生成。 – 2012-08-10 12:55:25

+0

从我的角度来看,这将是另一个考验。在这里,您只是测试它拒绝重复的promocodes。 – Nobita 2012-08-10 12:56:38

+0

好的。但是,这是我试图写在第一个地方的测试;) – 2012-08-10 12:57:33

0

此答案是基于您的意见:

我需要确保生成!生成一个代码 - 无论如何, 直到一个唯一的代码已经生成。

我觉得你可能很难正确测试这个。单元测试“无论发生什么”情况下无限循环可能是一个棘手的问题。

我不知道如何做到这一点,因为我不能真正地存根.generate方法返回固定值(因为那样它会卡在一个无限循环)。

考虑的一种可能性可能是,如果您不是同时尝试这两种方法,而是尝试了两种方法? (也就是说,在某些情况下找到一种方法使它返回一个固定的数字,并最终触发实际的随机数。一个实例变量计数器可能会有所帮助;将其设置为一个随机数,将其计数,当它大于零时返回固定号码,或沿着这些线路的东西)。尽管如此,这仍然不是一个完美的测试,或者甚至是一个非常好的测试。

可能更值得寻找生成类似字符串的方法,这些字符串很可能是唯一的,并且有一些数学证明是这样的。我并不是说这是最实际的想法,但是如果你真的需要证明(就像你试图用测试那样),它可能是更可能的解决方案。