【问题标题】:Testing "validates ..., format => with"测试“验证 ...,格式 => 与”
【发布时间】:2013-01-27 05:09:48
【问题描述】:

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

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

结束 结束

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

我不想测试它是否使用了一些正则表达式,因为那样我将测试实现而不是行为,而且我也不想只测试一个硬编码的情况。

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

编辑:另一个问题,如何生成无效的随机名称?有没有办法创建在允许值之外至少包含一个字符的随机名称?我不能硬编码一个包含所有无效值的数组来随机化它,因为它太大了

【问题讨论】:

    标签: rspec rspec-rails


    【解决方案1】:

    查看开源项目 Shoulda Matchers: https://github.com/thoughtbot/shoulda-matchers

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

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

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

    【讨论】:

      【解决方案2】:

      为了测试有效和无效格式(我认为正则表达式可以定义要验证的格式),如何在一些帮助实用程序方法中定义您认为有效和无效的名称,您可能会随着时间的推移对其进行改进如有必要。例如:

      spec/support/utilities.rb

      def valid_names
        %w[Homer bart LISA]
      end
      
      def invalid_names
        %w[BuRn$ 5M1+h3Rs♡]
      end
      

      然后,您可以使用 RSpec、shoulda-matchersFactory Girl:name(和 :lastname)编写测试,如下所示:

      spec/models/user_spec.rb

      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
      

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

      【讨论】:

      • 但是这样我只测试几个案例,我想用最通用的方法测试尽可能多的案例(这就是我想生成随机名称的方式)
      • 我认为仅以与正则表达式匹配的方式生成随机字符串并不能确定您真正需要测试的内容。您的正则表达式测试带有大写/小写字母的名称。这意味着您需要测试您的有效案例,这将是一个只有小写、只有大写以及两者组合的字符串,并使用字符串中的数字、符号和其他字符来测试您的无效案例。如果你真的想做随机字符串生成器,你需要为每个需要测试的情况使用一个,在我看来,它不会提供比静态字符串更多的价值。
      • 问题是,TDD 告诉首先做测试,然后只做需要的代码来通过测试。如果我有 3 个测试用例(下限、上限、组合),我可以硬编码 3 个值并且测试会通过(我知道这样做没有意义,但我试图将 TDD 方法发挥到极致:P )。必须有某种方法来进行测试以使您得出该正则表达式,而不是对正则表达式的测试,而是使您使用该正则表达式的测试。
      【解决方案3】:

      针对随机数据进行测试是一种常见的测试技术,称为Fuzzing。我会考虑使用 FuzzBert's 生成器来创建真正的随机二进制数据以进行测试。

      这是一些您不希望通过验证的出色随机数据的示例。

      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 每隔一段时间都会失败,请查看失败的字符串,如果它是有效字符串,则重新运行。

      测试所有可能性

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

      【讨论】:

      • 谢谢,这符合我需要做的事情,我会检查正则表达式以确保随机名称无效,我不希望测试在某些情况下失败,因为测试将自动运行,我不想得到错误的错误
      猜你喜欢
      • 2020-09-23
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 2012-06-29
      • 2012-03-02
      • 2020-10-23
      • 1970-01-01
      • 2022-11-13
      相关资源
      最近更新 更多