Rspec “测试”;验证…,格式=>;加上;

Rspec “测试”;验证…,格式=>;加上;,rspec,rspec-rails,Rspec,Rspec Rails,我有一个具有此验证的用户模型 validates :name, :lastname, :format => {:with => /^[a-zA-Z]+$/, :message => 'Only letters and spaces allowed.'} 我不知道如何正确地测试它 我已经完成了一个函数,它返回一个由a-zA-z字符数组中的10个字符组成的随机字符串 def get_random_name "abcdefghijklmnopqrstuvwxyzABCDEFGH

我有一个具有此验证的用户模型

validates :name, :lastname, :format => {:with => /^[a-zA-Z]+$/, :message => 'Only letters and spaces allowed.'}
我不知道如何正确地测试它

我已经完成了一个函数,它返回一个由a-zA-z字符数组中的10个字符组成的随机字符串

def get_random_name
  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split('').shuffle[0..10].join
结束 结束

然后每次运行我的规格都会得到一个新名称

我不想测试它是否使用了一些regexp,因为这样我将测试实现而不是行为,我也不想只测试一个硬编码的情况

我的问题是:我应该这样做吗?真的需要吗?是更好还是没用?你知道有什么更好的方法来测试这种验证吗


编辑:另一个问题,如何生成无效的随机名称?是否有一种方法可以创建至少包含一个超出允许值的字符的随机名称?我不能硬编码一个包含所有无效值的数组来随机化,因为为了测试有效和无效格式,数组太大了(我认为正则表达式可以定义一种格式来验证),在一些辅助工具实用程序方法中定义您认为有效和无效的名称如何?如果需要,您可以随时间改进这些方法。例如:

spec/support/utilities.rb

def valid_names
  %w[Homer bart LISA]
end

def invalid_names
  %w[BuRn$ 5M1+h3Rs♡]
end
describe User do

  let(:user) { FactoryGirl.create(:user) }

  # ...

  describe "validations" do
    context "for name, lastname" do
      context "when format is invalid" do
        invalid_names.each do |invalid_name|
          it { should_not allow_value(invalid_name).for(:name) }
          it { should_not allow_value(invalid_name).for(:lastname) }
        end
      end

      context "when format is valid" do
        valid_names.each do |valid_name|
          it { should allow_value(valid_name).for(:name) }
          it { should allow_value(valid_name).for(:lastname) }
        end
      end
      # ...
    end
    # ...
  end
  # ...
end
然后,您可以使用RSpec为
:name
(和
:lastname
)编写测试,如下所示:

规格/型号/用户规格rb

def valid_names
  %w[Homer bart LISA]
end

def invalid_names
  %w[BuRn$ 5M1+h3Rs♡]
end
describe User do

  let(:user) { FactoryGirl.create(:user) }

  # ...

  describe "validations" do
    context "for name, lastname" do
      context "when format is invalid" do
        invalid_names.each do |invalid_name|
          it { should_not allow_value(invalid_name).for(:name) }
          it { should_not allow_value(invalid_name).for(:lastname) }
        end
      end

      context "when format is valid" do
        valid_names.each do |valid_name|
          it { should allow_value(valid_name).for(:name) }
          it { should allow_value(valid_name).for(:lastname) }
        end
      end
      # ...
    end
    # ...
  end
  # ...
end

如果你将来打算将你的应用程序国际化,请记住,并非所有世界名称都符合此格式。

针对随机数据进行测试是一种常见的测试技术,称为。我将研究如何使用生成器创建真正的随机二进制数据来进行测试

下面是一些您不希望通过验证的伟大随机数据的示例

irb> require 'fuzzbert'
       => true
irb> test_string = FuzzBert::Generators.random_fixlen(10)[]
       => "S\x1EU1\x11HVY\x0E\xD0"
irb> puts test_string
     S▲U1◄HVY♫�
       => nil
随机性很好

因为它是将随机二进制位转换成字符串,所以您将得到一些非常有趣的结果来进行测试。这是一件好事!它不仅可以测试使用诸如?之类的已知符号,还可以测试各种有效和无效字符的组合

随机有时有效

虽然不太可能,但您仍有可能不时获得有效数据。此外,创建的随机字符串越长,获得有效数据的几率越低

解决这个问题的第一个尝试可能是在每个输出中添加一个无效字符,但我不建议这样做。例如,如果您总是附加“!”,那么它将使您的测试等同于确保字符串中没有“!”,而不是完整正则表达式可能性的真正测试

我建议您针对同一个正则表达式测试随机字符串,如果它确实通过了测试,则生成一个不同的字符串进行测试

最后,您可以忽略随机数据有效的罕见机会。如果此特定rspec每隔一段时间失败一次,请查看失败的字符串,如果它是有效字符串,则只需重新运行

测试所有可能性


您永远无法测试所有无效字符串(除非您的最大长度较短),但通过使用模糊测试,您将能够针对包含大量有效和无效字符的字符串进行测试。

签出开源项目Shoulda Matchers:

编辑:抱歉,刚刚注意到Paul Fioravanti也提到了Shoulda。但是,您不需要使用FactoryGirl来创建模型的实例。验证测试不需要使用
create

您可以直接在模型上创建单元测试:


describe User, 'Validations' do
  it { should allow_value("Name").for(:name) }
  it { should_not allow_value("Inv4lid_").for(:name) }
end

但是那样的话,我将只测试几个案例,我想用最通用的方法测试尽可能多的案例(这就是我想生成随机名称的方法),我认为仅仅以与正则表达式匹配的方式生成一个随机字符串并不能精确指出您真正需要测试的内容。你的正则表达式测试一个带有大写/小写字母的名字。这意味着您需要测试有效的大小写,这将是一个只包含较低大小写的字符串,以及两者的组合,并使用字符串中的数字、符号和其他字符测试无效的大小写。如果你真的想做随机字符串生成器,你需要为每一个需要测试的情况都做一个,在我看来,它提供的值并不比静态字符串多。问题是,TDD告诉你先做测试,然后只做需要的代码来通过测试。如果我有3个测试用例(较低、较高、组合),我可以硬编码这3个值,测试就会通过(我知道这样做没有意义,但我试图将TDD方法考虑到极端:P)。必须有某种方法来进行测试,以使您得到该regexp,而不是针对regexp的测试,让您使用该regexp的测试。谢谢,这符合我需要做的,我将根据regexp进行检查,以确保随机名称无效,我不希望在某些情况下测试失败,因为测试将自动运行,我不想犯错误