mbigras mbigras - 6 months ago 18
Ruby Question

Why is my guard-rspec test failing?

I set up my

guard-rspec
environment using the techniques described in this tutorial. I'm also practicing namespacing as described in Programing Ruby starting on page 240. My current project directory is on github in the
stack-overflow-question
branch.
I'm using:

❯ 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


I'm running a test in
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


However it's failing:

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)>


But I have no idea why because the class
RubyBulletinBoard::Thread
does exist in
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


Even weirder, when I uncomment line 2 in
lib/ruby_bulletin_board/runner.rb
the test passes:

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 output:

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)>


It seems to me that including requiring
thread.rb
in
runner.rb
would have nothing to do with my tests.


  1. Why is my original test in
    spec/thread_spec.rb
    failing?

  2. Why does uncommenting line 2 in
    lib/runner.rb
    cause the test to pass?



Thanks for your help :)

Edit:

The accepted answer helped me get things up and running, more questions can be found in another post

Answer

A few things here:

  1. When you're running specs, you're running RSpec like an application and it's "config" is in spec/spec_helper.rb. I'll assume it's empty/irrelevant.

  2. If you're running a more recent version of RSpec, you can just place --require spec_helper in your .rspec file and you won't need the require "spec_helper" in your files.

  3. It's best to use RSpec.describe instead of plain describe the first time in a file.

  4. You can use a subject block for more readability along with described_class. It also lets you use it { is.expected_to syntax

  5. describe can take a class name instead of a string. This way it makes it obvious if you've required the file or not. If you pass a class, then subject becomes implicit.

Since RSpec is like a separate app, it doesn't include your own library files by default (newer versions of RSpec do add lib to LOAD_PATH). So your tests have to individually require any files they test, e.g.

require 'spec_helper'

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

becomes:

require 'ruby_bulletin_board/thread'

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

If the above require fails, it means you need to put lib in your load path. Check your spec/spec_helper.rb if that's the case.

If your spec/spec_helper.rb is empty (or doesn't have anything important), you may want remove it along with .rspec and run rspec --init to generate a good started template for you. Be sure you uncomment the =begin and =end sections there.