Rails - RSpec NoMethodError:未定义的方法

Posted

技术标签:

【中文标题】Rails - RSpec NoMethodError:未定义的方法【英文标题】:Rails - RSpec NoMethodError: undefined method 【发布时间】:2017-12-09 03:43:36 【问题描述】:

我正在尝试测试一种非常简单的方法,该方法接受 2 个数字并使用它们来计算百分比。但是,当我尝试运行测试时,它会失败并出现以下错误:

NoMethodError: undefined method `pct' for Scorable:Module
./spec/models/concerns/scorable_spec.rb:328:in `block (2 levels) in 
<top (required)>'
./spec/rails_helper.rb:97:in `block (3 levels) in <top (required)>'
./spec/rails_helper.rb:96:in `block (2 levels) in <top (required)>'
-e:1:in `<main>'

这是我的模块规范文件:

require 'rails_helper'
RSpec.describe Scorable, :type => :concern do

  it "pct should return 0 if den is 0 or nil" do
    expect(Scorable.pct(nil, 15)).to eq(0)
    expect(Scorable.pct(0, 15)).to eq(0)
  end

end

这是位于 Scorable.rb 中的 pct 方法:

def pct(num,den)
  return 0 if num == 0 or num.nil?
  return (100.0 * num / den).round
end

这是我的 rspec_helper:

 if ENV['ENABLE_COVERAGE']
   require 'simplecov'
   SimpleCov.start do
   add_filter "/spec/"
   add_filter "/config/"
   add_filter '/vendor/'

   add_group 'Controllers', 'app/controllers'
   add_group 'Models', 'app/models'
   add_group 'Helpers', 'app/helpers'
   add_group 'Mailers', 'app/mailers'
   add_group 'Views', 'app/views'
 end
end

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
  expectations.include_chain_clauses_in_custom_matcher_descriptions = 
  true
end
config.raise_errors_for_deprecations!

 config.mock_with :rspec do |mocks|
   mocks.verify_partial_doubles = true
 end
end

我对 RSpec 非常陌生,并且已经为这个问题困惑了一天多。它肯定指向一个现有方法,因为当我在 RubyMine 中使用 Go To Declaration 时,它会打开方法声明。任何人都可以为我解释一下这个吗?我确定我忽略了一些非常简单的事情。

【问题讨论】:

请出示Scorable模块的源码,具体是pct方法。 Rubymine 并不完美... @mudasobwa 已使用该方法定义更新了问题。 【参考方案1】:

要使模块方法可以用Module.method 表示法调用,应该在模块范围内声明。

module Scorable
  def self.pct(num,den)
    return 0 if num == 0 or num.nil?
    return (100.0 * num / den).round
  end
end

或:

module Scorable
  class << self
    def pct(num,den)
      return 0 if num == 0 or num.nil?
      return (100.0 * num / den).round
    end
  end
end

Module#module_function:

module Scorable
  module_function
  def pct(num,den)
    return 0 if num == 0 or num.nil?
    return (100.0 * num / den).round
  end
end

注意,后者在该模块中声明了模块方法和普通实例方法。


旁注: 在方法的最后一行使用return 被认为是代码异味,应该避免:

module Scorable
  def self.pct(num,den)
    return 0 if num == 0 or num.nil?
    (100.0 * num / den).round
  end
end

【讨论】:

啊,谢谢!我不敢相信事情就这么简单。我一定会记得 module_function 的事情。模块和实例方法仍然经常让我在 Rails 中遇到问题。关于退货声明,这是我正在努力摆脱的一个非常糟糕的习惯。我来自 C# 背景,并在 1 1/2 个月前开始使用 Rails,但我的直觉仍然经常反对许多 Rails 约定。

以上是关于Rails - RSpec NoMethodError:未定义的方法的主要内容,如果未能解决你的问题,请参考以下文章

Rails 5,Rspec:架构中未找到环境数据

设置 RSpec 以测试 gem(不是 Rails)

rails-rspec 错误无法加载此类文件 -- rspec/core/formatters/progress_formatter

Rails/Rspec:测试延迟作业邮件

Rails:在 RSpec 测试查看编辑表单时出错

Rails 3.1,RSpec:测试模型验证