为什么我的 guard-rspec 测试失败了?

Why is my guard-rspec test failing?

我使用 stack-overflow-post 分支中 this tutorial. I'm also practicing namespacing as described in Programing Ruby starting on page 240. My current project directory is on github 中描述的技术设置了我的 guard-rspec 环境。 我正在使用:

❯ ruby -v
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-darwin15.0]
❯ rbenv -v                                                            
rbenv 1.0.0
❯ rbenv versions                                                      
  system
* 2.1.1 (set by /Users/max/Google Drive/devbootcamp/phase-0-ruby-bulletin-board/.ruby-version)
  2.1.5
  2.2.3
  2.3.1
❯ bundle exec guard -v                                                
Guard version 2.3.0

我 运行 在 spec/thread_spec.rb 参加考试:

require 'spec_helper'

describe 'RubyBulletinBoard::Thread' do
    let (:thread) { RubyBulletinBoard::Thread.new }
    it { expect(thread).to be_kind_of(RubyBulletinBoard::Thread) }    

#     it 'has a valid uuid' do
#         p thread.uuid
#         expect(thread.uuid).to be_kind_of(String)
#     end

#     it 'has editable title' do
#         default_title = thread.title
#         thread.title = "#{default_title} something different"
#         new_title = thread.title
#         expect(default_title == new_title).to eq(false)
#     end    
end

但是失败了:

01:50:07 - INFO - Running: ./spec/thread_spec.rb:5
Run options: include {:locations=>{"./spec/thread_spec.rb"=>[5]}}

RubyBulletinBoard::Thread
  example at ./spec/thread_spec.rb:5 (FAILED - 1)

Failures:

  1) RubyBulletinBoard::Thread
     Failure/Error: let (:thread) { RubyBulletinBoard::Thread.new }
     NameError:
       uninitialized constant RubyBulletinBoard::Thread
     # ./spec/thread_spec.rb:4:in `block (2 levels) in <top (required)>'
     # ./spec/thread_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.00055 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/thread_spec.rb:5 # RubyBulletinBoard::Thread

[1] guard(main)>

但我不知道为什么,因为 class RubyBulletinBoard::Thread 确实存在于 lib/ruby_bulletin_board/thread.rb:

require_relative 'id'

module RubyBulletinBoard
    class Thread
        attr_reader :uuid
        attr_accessor :title

        def initialize
           @uuid = IdCreator.create_id
           @title = title 
        end
    end
end

更奇怪的是,当我在 lib/ruby_bulletin_board/runner.rb 中取消注释第 2 行时,测试通过了:

require_relative 'example'
# require_relative 'thread' # <--- THIS IS LINE 2

module RubyBulletinBoard
    class Runner
        attr_accessor :greeter, :thread

        def initialize
            @greeter = RSpecGreeter.new
            # @thread = RubyBulletinBoard::Thread.new
        end

        def run
            greeter.greet
            # p @thread.class
        end
    end
end

rspec 输出:

01:53:57 - INFO - Running: ./spec/thread_spec.rb:5
Run options: include {:locations=>{"./spec/thread_spec.rb"=>[5]}}

RubyBulletinBoard::Thread
  should be a kind of RubyBulletinBoard::Thread

Finished in 0.00114 seconds
1 example, 0 failures

[1] guard(main)>

在我看来,在 runner.rb 中包含要求 thread.rb 与我的测试无关。

  1. 为什么我在 spec/thread_spec.rb 中的原始测试失败了?
  2. 为什么取消注释 lib/runner.rb 中的第 2 行会导致测试通过?

感谢您的帮助:)

编辑:

接受的答案帮助我解决了问题 运行,更多问题可以在

中找到

编辑 2: 也刚刚有了一个大发现:我一直在使用一个名为 thread.rb 的文件,有一个名为 ruby class 的线程,所以当我一直在说 require 'thread'我的 thread_spec.rb 它一直给我错误:

[1] guard(main)>
17:57:09 - INFO - Running: spec/thread_spec.rb
/Users/max/Google Drive/devbootcamp/phase-0-ruby-bulletin-board/spec/thread_spec.rb:4:in `<top (required)>': uninitialized constant RubyBulletinBoard (NameError)
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1361:in `load'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1361:in `block in load_spec_files'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1359:in `each'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1359:in `load_spec_files'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:106:in `setup'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:92:in `run'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:78:in `run'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:45:in `invoke'
    from /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/exe/rspec:4:in `<top (required)>'
    from bin/rspec:17:in `load'
    from bin/rspec:17:in `<main>'
17:57:10 - ERROR - Failed: "bin/rspec -f progress -r /Users/max/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/guard-rspec-4.7.2/lib/guard/rspec_formatter.rb -f Guard::RSpecFormatter --failure-exit-code 2  spec/thread_spec.rb" (exit code: 1)

通过重命名 thread.rb -> rbb_thread.rb 然后我可以 require 'rbb_thread' 并且我将从红色变为绿色 :)

编辑 3: thread.rb 错误的另一种解决方案是 require_relative ../lib/thread,因此不需要重命名

这里有几件事:

  1. 当你运行宁规范时,你运行宁RSpec就像一个应用程序,它"config"在spec/spec_helper.rb。我假设它是 empty/irrelevant.

  2. 如果您运行正在使用 RSpec 的更新版本,您只需将 --require spec_helper 放入 .rspec 文件中即可您的文件中不需要 require "spec_helper"

  3. 最好在文件中第一次使用 RSpec.describe 而不是普通的 describe

  4. 您可以使用 subject 块来提高可读性以及 described_class。它还允许您使用 it { is.expected_to 语法

  5. describe 可以使用 class 名称而不是字符串。这样一来,您是否需要该文件就很明显了。如果传递 class,则 subject 变为隐式。

由于 RSpec 就像一个单独的应用程序,默认情况下它不包含您自己的库文件(RSpec 的较新版本确实将 lib 添加到 LOAD_PATH ).所以你的测试必须单独要求他们测试的任何文件,例如

require 'spec_helper'

describe 'RubyBulletinBoard::Thread' do
    let (:thread) { RubyBulletinBoard::Thread.new }
    it { expect(thread).to be_kind_of(RubyBulletinBoard::Thread) }    

变成:

require 'ruby_bulletin_board/thread'

RSpec.describe RubyBulletinBoard::Thread do
    it { is_expected.to be_kind_of(RubyBulletinBoard::Thread) }    

如果上面的require失败了,这意味着你需要把lib放在你的加载路径中。如果是这种情况,请检查您的 spec/spec_helper.rb

如果您的 spec/spec_helper.rb 是空的(或没有任何重要的东西),您可能需要将其与 .rspec 和 运行 rspec --init 一起删除以生成一个适合您的良好入门模板。请务必取消注释 =begin=end 部分。