Ruby:如何在Rspec测试中包含外部模块

时间:2017-10-11 21:50:52

标签: ruby rspec module

我有2个项目,一个“公共代码”项目,我已经把它变成了一个大模块,可以引入其他模块:

以下是“my-common-project”的文件夹结构:

  • 我的常见项目
    • 通用
      • file_utils.rb
      • 其余-client.rb
      • 其他带模块的ruby文件......
    • common.rb
    • 的Gemfile
    • 等...

common.rb

require 'bundler'
Bundler.require
require_relative './common/file-utils.rb'
require_relative './common/rest_client.rb'
...

module Common
  include FileUtils
  include RestClient
  # include other modules here...

file_utils.rb

module Common
  module FileUtils

    def open_file(file_name)
      dir = File.expand_path('') << '/lib'
      FileUtils.mkdir_p(dir) unless File.directory?(dir)
      File.open(File.expand_path('') << "/lib/#{file_name}", 'w')
    end
  end
end

我还有一个Rspec项目,我正在做一个测试:

  • 我-rspec的项目
    • 规范
      • my_test_spec.rb
      • spec_helper.rb
      • LIB
        • my_class.rb
    • .rspec
    • 的Gemfile
    • 等...

spec_helper.rb

require 'bundler'
require 'csv'
require_relative './lib/fp_relationship_api'
require_relative './../../../../../RubyProjects/mksta-common/common'

Bundler.require

RSpec.configure do |config|
  ...
  config.include Common
  ...
end

my_class.rb

require "#{File.expand_path('') << '/spec_helper'}"

class MyClass

include Common

  @error_file = open_file('error_file.txt')
  ...
end

我收到错误:

  

MyClass的未定义方法`open_file':Class(NoMethodError)

有人能看出出了什么问题吗?

1 个答案:

答案 0 :(得分:1)

我应该立即看到问题,但没有。你看到了:

之间的区别
lib/my_class.rb:9:in `<class:MyClass>': undefined method `open_file' for MyClass:Class (NoMethodError)

open_file出现在MyClass的正文中时,并且:

lib/my_class.rb:16:in `m': undefined method `open_file' for #<MyClass:0x007fbb0d10cc30> (NoMethodError)

如果我把它放在def

def m
    @error_file = open_file('error_file.txt')

在第一种情况下,您位于MyClass的正文中,其中open_file未定义。在第二种情况下,我删除了include Common

为了进行研究,我已经定义了重现错误所需的最低限度。 文件.../lib/file_utils.rb,与您的相同。

档案.../lib/common.rb

require_relative 'file_utils'

module Common
    puts "Common instance methods before include : #{instance_methods(true).sort}"
    include FileUtils
    puts "Common instance methods after  include : #{instance_methods(true).sort}"

    puts "Common class methods before extend : #{singleton_methods(true).sort}"
    extend FileUtils
    puts "Common class methods after  extend : #{singleton_methods(true).sort}"
end

档案.../lib/my_class.rb

require_relative 'common'

class MyClass
#    puts "MyClass methods before include : #{instance_methods(true).sort}"
    include Common
#    puts "MyClass methods after  include : #{instance_methods(true).sort}"

    puts "self=#{self}"
    puts "MyClass class methods before extend : #{singleton_methods(true).sort}"
    extend Common
    puts "MyClass class methods after  extend : #{singleton_methods(true).sort}"
    @error_file = open_file('error_file.txt')
    puts "in MyClass error_file=#{@error_file}"

    def m
        @error_file = open_file('error_file.txt')
        puts "in m error_file=#{@error_file}"
    end
end

MyClass.new.m

执行:

$ ruby -w lib/my_class.rb 
Common instance methods before include : []
Common instance methods after  include : [:open_file]
Common class methods before extend : []
Common class methods after  extend : [:open_file]
self=MyClass
MyClass class methods before extend : []
MyClass class methods after  extend : [:open_file]
in MyClass error_file=#<File:0x007ff2621fcdc0>
in m error_file=#<File:0x007ff2621fc938>

<强>解释

由于您使用@error_file = open_file('error_file.txt')的方式,您位于MyClass的主体中,仅在解释器读取类定义时执行。open_file。如果在没有接收器的情况下使用self之类的方法,则会将其发送到隐式接收器MyClass,即open_file。但是在定义时,def self.open_file(file_name) 不是类方法,而是实例方法。

如果需要类方法(更确切地说是单例方法),则必须将其定义为

extend <module>

或使用"dynamic_templates": [ { "message_field": { "match": "message", "match_mapping_type": "string", "mapping": { "fielddata": { "format": "disabled" // PROBLEM HERE! }, "index": "analyzed", "omit_norms": true, "type": "string" } } },