[rspec-devel] [ rspec-Bugs-7805 ] Stubs aren't being removed from modules

noreply at rubyforge.org noreply at rubyforge.org
Fri Feb 2 12:53:55 EST 2007


Bugs item #7805, was opened at 2007-01-14 01:59
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3149&aid=7805&group_id=797

Category: mock module
Group: None
>Status: Closed
>Resolution: Accepted
Priority: 3
Submitted By: Michal Kwiatkowski (infrared)
>Assigned to: David Chelimsky (dchelimsky)
Summary: Stubs aren't being removed from modules

Initial Comment:
Stubs aren't removed after running specs, which doesn't break things for modules begin tested, but can be source of bugs if you're stubbing classes from stdlib. Example code stubs File.open and manages to break RSpec code itself. Place attached Rakefile and spec in the same directory, then run "rake --trace" to see:

undefined method `<' for nil:NilClass
/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/lib/spec/rake/verify_rcov.rb:42:in `define'

Source of this error is 'total_coverage' variable which doesn't get initialized because File.open doesn't yield nor return anything useful (because it's still stubbed).

As you see in the stack report, I'm using rspec 0.7.5.

----------------------------------------------------------------------

>Comment By: David Chelimsky (dchelimsky)
Date: 2007-02-02 17:53

Message:
This was fixed when [#8302] was fixed.

Trunk rev 1447.

----------------------------------------------------------------------

Comment By: Michal Kwiatkowski (infrared)
Date: 2007-01-20 00:21

Message:
Can anyone confirm this bug? I found even a simpler example:

-----
$ ls
mock_on_file_causes_error.rb  Rakefile
$ cat Rakefile
require 'spec/rake/spectask'
require 'spec/rake/verify_rcov'

Spec::Rake::SpecTask.new(:spec_with_rcov) do |t|
  t.spec_files = FileList['mock_on_file_causes_error.rb']
  t.rcov = true
end

RCov::VerifyTask.new(:verify_rcov => :spec_with_rcov) do |t|
  t.threshold = 100
end

task :default  => :verify_rcov
$ cat mock_on_file_causes_error.rb
require 'rubygems'
require 'spec'

context "mocks" do
  specify "mock the File class" do
    File.should_not_receive :open
  end
end
$ rake
(in /tmp/blah)
rm -r coverage
/usr/bin/ruby1.8
-I"/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/lib" -S rcov
--exclude lib\/spec,bin\/spec -o "coverage"
"/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/bin/spec" --
"mock_on_file_causes_error.rb"

.

Finished in 0.002439 seconds

1 specification, 0 failures
Coverage: % (threshold: 100%)
rake aborted!
undefined method `<' for nil:NilClass

(See full trace by running task with --trace)
-----

As you can see not only stubbing, but mocking as well causes
errors.

----------------------------------------------------------------------

Comment By: Michal Kwiatkowski (infrared)
Date: 2007-01-14 11:22

Message:
The bug seems to occur only in conjunction with rake and/or
rcov but stack trace originates from rspec code (file
spec/rake/verify_rcov.rb, line 42), within define of
VerifyTask, which is run by rake only *after* the spec task
completes (see the attached Rakefile). So it's not true that
this code is run during the spec.

Error presented by me isn't the only one that can happen
because of stubbing File.open. Let me show you another one:

Spec file contains (attached as spec_that_coredumps.rb):

require 'rubygems'
require 'spec'

context "stubs" do
  specify "1 - stub the open method" do
    puts "BEFORE spec 1"
    File.stub!(:open).and_return("something")
    File.open.should == "something"
    puts "AFTER spec 1"
  end
  specify "2 - use File.open to create example.txt" do
    puts "BEFORE spec 1"
    File.open.should == "something"
    puts "AFTER spec 2"
  end
end

After running "rake --trace" I get a core dump:

$ rake --trace
(in /tmp/foobar)
** Invoke default (first_time)
** Invoke verify_rcov (first_time)
** Invoke spec_with_rcov (first_time)
** Invoke clobber_spec_with_rcov (first_time)
** Execute clobber_spec_with_rcov
rm -r coverage
** Execute spec_with_rcov
/usr/bin/ruby1.8
-I"/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/lib" -S rcov
--exclude lib\/spec,bin\/spec -o "coverage"
"/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/bin/spec" -- "foo.rb"

BEFORE spec 1
AFTER spec 1
.BEFORE spec 1
[BUG] Segmentation fault
ruby 1.8.4 (2005-12-24) [i486-linux]

rake aborted!
Command failed with status (): [/usr/bin/ruby1.8
-I"/usr/lib/ruby/gems/1.8...]
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:722:in `sh'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:729:in `sh'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:812:in `sh'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:807:in `sh'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:747:in `ruby'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:812:in `ruby'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:807:in `ruby'
/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/lib/spec/rake/spectask.rb:131:in
`define'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:831:in
`verbose'
/usr/lib/ruby/gems/1.8/gems/rspec-0.7.5/lib/spec/rake/spectask.rb:110:in
`define'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:387:in
`execute'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:387:in
`execute'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:357:in
`invoke'
/usr/lib/ruby/1.8/thread.rb:135:in `synchronize'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:350:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:364:in
`invoke_prerequisites'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:999:in `each'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:363:in
`invoke_prerequisites'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:356:in
`invoke'
/usr/lib/ruby/1.8/thread.rb:135:in `synchronize'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:350:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:364:in
`invoke_prerequisites'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:999:in `each'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:363:in
`invoke_prerequisites'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:356:in
`invoke'
/usr/lib/ruby/1.8/thread.rb:135:in `synchronize'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:350:in
`invoke'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:1906:in `run'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:1906:in `run'
/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/bin/rake:7
/usr/bin/rake:18

If stub would be removed and state in the begining of spec2
would be exactly the same as before running spec1 error
should not happen.

Making spec2 the first spec in context will yield expected
result: ArgumentError from File.open.

Also, changing a line in spec2 to other that doesn't involve
File.open will stop rake from coredumping, but original
"undefined method `<' for nil:NilClass" error will still be
there.

Any ideas?

----------------------------------------------------------------------

Comment By: David Chelimsky (dchelimsky)
Date: 2007-01-14 05:04

Message:
There is a problem here but it is different from what you suggest.

I created a file called stubs_should_restore_methods.rb (attached). Here's the code and the command line session:

require 'spec'

context "stubs" do
  specify "1 - stub the open method" do
    File.stub!(:open).and_return("something")
    File.open.should == "something"
  end
  specify "2 - use File.open to create example.txt" do
    filename = "example-#{Time.now.to_i}.txt"
    file = File.open(filename,'w')
    file << "some text"
    file.close
  end
end

[david at mac tmp]$ ls -al
total 0
drwxr-xr-x   2 david  david   68 Jan 13 23:01 .
drwxr-xr-x   9 david  david  306 Jan 13 23:01 ..
[david at mac tmp]$ mv ../stubs_should_restore_methods.rb .
[david at mac tmp]$ ls -al
total 8
drwxr-xr-x   3 david  david  102 Jan 13 23:02 .
drwxr-xr-x   8 david  david  272 Jan 13 23:02 ..
-rw-r--r--   1 david  david  348 Jan 13 22:54 stubs_should_restore_methods.rb
[david at mac tmp]$ ruby stubs_should_restore_methods.rb -fs

stubs
- 1 - stub the open method
- 2 - use File.open to create example.txt

Finished in 0.001414 seconds

2 specifications, 0 failures
[david at mac tmp]$ ls -al
total 16
drwxr-xr-x   4 david  david  136 Jan 13 23:02 .
drwxr-xr-x   8 david  david  272 Jan 13 23:02 ..
-rw-r--r--   1 david  david    9 Jan 13 23:02 example-1168750953.txt
-rw-r--r--   1 david  david  348 Jan 13 22:54 stubs_should_restore_methods.rb
[david at mac tmp]$ ruby stubs_should_restore_methods.rb -fs

stubs
- 1 - stub the open method
- 2 - use File.open to create example.txt

Finished in 0.001393 seconds

2 specifications, 0 failures
[david at mac tmp]$ ls -al
total 24
drwxr-xr-x   5 david  david  170 Jan 13 23:02 .
drwxr-xr-x   8 david  david  272 Jan 13 23:02 ..
-rw-r--r--   1 david  david    9 Jan 13 23:02 example-1168750953.txt
-rw-r--r--   1 david  david    9 Jan 13 23:02 example-1168750963.txt
-rw-r--r--   1 david  david  348 Jan 13 22:54 stubs_should_restore_methods.rb

As you can see, each time the spec is run, the second spec creates a new file using File.open, even though File.open had been stubbed in the first spec.

I think the problem is that rcov is trying to use File.open to create and/or write to a file DURING the spec. If that's correct, I don't see what we would be able to do about that from RSpec.

What do you think?

Cheers,
David

----------------------------------------------------------------------

You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3149&aid=7805&group_id=797


More information about the rspec-devel mailing list