【问题标题】:RSpec to test raise exception in railsRSpec 测试 Rails 中的引发异常
【发布时间】:2016-10-26 05:14:38
【问题描述】:

我是 RSpec 的新手。我的模型 user_profile.rb 中有一个方法

def self.create_from_supplement(device, structure)
  xml = Nokogiri.parse(structure.to_s)
  user_profile = nil
  auth_type = xml.%('auth_supplement/auth_type').inner_html

  if 'user' == auth_type
    user_details_str = xml.%('auth_supplement/supplement_data/content').inner_html rescue nil

    return nil if user_details_str.blank?

    user_details_xml = Nokogiri.parse(user_details_str)
    user_name = user_details_xml.%('username').inner_html

    user_profile = UserProfile.find_or_initialize_by(name: user_name)

    if user_profile.save
      device.update_attributes(user_profile_id: user_profile.id)
    else
      raise "User Profile Creation Failed because of #{user_profile.errors.full_messages}"
    end

  end

  return user_profile
end

我正在编写一个单元测试用例来测试 user_profile.save 失败时,测试用例会期望引发异常。但是在我的 user_profiles 表中,我只有一列:name。

user_profile.save 失败时如何测试案例? 这里最重要的问题是我没有找到任何方法让这个 user_profile.save 失败。

有些人建议使用 RSpec 存根。我们如何做到这一点?

【问题讨论】:

    标签: ruby-on-rails ruby rspec exception-handling


    【解决方案1】:

    对于 Rspec 期望,当您期望引发错误时,您有一个特殊的语法。

    如果你做了这样的事情:

    expect(raise NoMethodError).to raise_error(NoMethodError)
    

    这行不通 - RSpec 不会处理错误并退出。

    但是如果你使用括号:

    expect { raise NoMethodError }.to raise_error(NoMethodError)
    

    应该会过去的。

    如果您使用方括号(或 do / end 块),则块中的任何错误都将被“捕获”,您可以使用 raise_error 匹配器检查它们。

    【讨论】:

      【解决方案2】:

      签出 rspec 文件:

      https://www.relishapp.com/rspec/rspec-expectations/v/2-11/docs/built-in-matchers/raise-error-matcher

      describe ':: create_from_supplement' do
        it 'blows up' do
          expect { UserProfile.create_from_supplement(*args) }.to raise_error(/User Profile Creation Failed because of/)
        end
      end
      

      追溯您的代码,这里是可能导致错误的地方,并遵循您可以考虑的内容。

      1. user_details_str = xml.%('auth_supplement/supplement_data/content').inner_html

      这里的user_details_str 可能是无效的字符串格式(不是零),因为您从'auth_supplement/supplement_data/content' 得到的任何内容都不是正确的格式。

      1. user_details_xml = Nokogiri.parse(user_details_str)

      您需要在此处确定可能导致Nokogiri::parse 为您提供无效结果的原因。

      1. user_name = user_details_xml.%('username').inner_html

      那么这里,同上。

      1. user_profile = UserProfile.find_or_initialize_by(name: user_name)

      因此,由于前面的几行代码,您可能有一个无效的user_name,这违反了您可能拥有的任何验证(例如,太短、未大写或其他)。

      更多信息

      因此,这可以深入到您的代码中。很难测试,因为您的方法试图做太多事情。这显然违反了 abc 大小(逻辑分支太多,更多信息在这里:http://wiki.c2.com/?AbcMetric)

      我建议将此方法的一些分支重构为更小的单一职责方法。

      【讨论】:

      • 这里的问题是如何让user_profile.save失败?
      猜你喜欢
      • 2014-04-04
      • 2015-11-28
      • 1970-01-01
      • 2019-03-12
      • 2019-03-09
      • 1970-01-01
      • 2016-05-28
      • 2019-03-22
      • 1970-01-01
      相关资源
      最近更新 更多