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

现在我想编写一个规范来测试生成的字符串的唯一性。.generate只要生成了不存在的 PromoCode,就应该调用该方法。

我不确定如何执行此操作,因为我无法真正删除.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

4 回答 4

3

那么类似的东西呢:创建一个PromoCode,保存结果,并尝试使用前一个对象创建一个新PromoCode的:codePromoCode

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

另外,这是模型级别,我假设您在数据库中有一个键可以使您免于竞争条件...

于 2012-08-10T12:51:30.820 回答
3

Rspec 的and_return方法允许您指定将循环通过的多个返回值

例如你可以写

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

这将导致第一次调用 generate 返回“badcode1”,第二个“badcode2”等...然后您可以检查返回的促销代码是否使用正确的代码创建。

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

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

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

于 2012-08-10T13:20:15.383 回答
0

如果您将促销代码保存在数据库中,您将在模型中为 uniq 促销代码添加验证。因此,您也可以在 rspec 中进行相同的测试。

像这样,

it { should validate_uniqueness_of(:promocode) }
于 2012-08-10T12:16:42.940 回答
0

此答案基于您的评论:

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

我觉得你可能很难正确测试这个。单元测试“无论如何”具有无限循环的情况可能有点棘手。

我不确定如何执行此操作,因为我无法真正删除 .generate 方法以返回固定值(因为它会陷入无限循环)。

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

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

于 2012-08-10T13:15:55.767 回答