如何测试优惠券/促销代码的唯一性?

时间:2012-08-10 11:59:10

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

我有一个模型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

任何指示赞赏。

4 个答案:

答案 0 :(得分:3)

如下所示:创建PromoCode,保存结果,然后尝试使用上一个PromoCode对象的code创建新的PromoCode:< / p>

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

此外,这是模型级别,我假设您在数据库中有一个密钥,可以帮助您避免竞争条件......

答案 1 :(得分:3)

Rspec&#39; and_return方法允许您指定将循环的多个返回值

例如你可以写

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

这将导致第一次调用生成以返回&#39; badcode1&#39;,第二个&#39; badcode2&#39;等等......然后,您可以检查返回的promocode是否使用正确的代码创建。

如果您想成为竞争条件证明,您将需要数据库唯一性约束,因此您的代码可能实际上想要

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

在您的规范中,您将存根创建!提高第一次但第二次返回值的方法

答案 2 :(得分:0)

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

像这样,

it { should validate_uniqueness_of(:promocode) }

答案 3 :(得分:0)

此答案基于您的评论:

  

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

我觉得你可能很难正确地测试它。无限循环的单元测试“无论什么”情况都可能是一个棘手的主题。

  

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

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

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