Error when mocking a method in a class


#1

I am fighting with an error using rspec-on-rails-matchers.

I have a model called “Centro” based in this table

create_table “centros”, :force => true do |t|
t.string “nombre”
t.string “cif”
t.string “domicilio”
t.string “codigo_postal”
t.string “poblacion”
t.string “provincia”
t.string “subdominio”
t.datetime “created_at”
t.datetime “updated_at”
endd

And I want to spec that the ‘nombre’ field should be unique.

describe Centro do

before(:each) do
@centro = Centro.new
end

it do
@centro.should validate_uniqueness_of(:nombre)
end

end

and the model:

class Centro < ActiveRecord::Base
validates_uniqueness_of :nombre
end

This should pass but I have the error:
1)
‘Centro should model to validate the uniqueness of nombre’ FAILED
expected “model to validate the uniqueness of nombre” but got #<Centro
id: nil, nombre: nil, cif: nil, domicilio: nil, codigo_postal: nil,
poblacion: nil, provincia: nil, subdominio: nil, created_at: nil,
updated_at: nil>
./spec/models/centro_spec.rb:18:

I have inspect the validate_uniqueness_of method and try several things
until I think I found the culprit.

The original code, that fails

def validate_uniqueness_of(attribute)
return simple_matcher(“model to validate the uniqueness of
#{attribute}”) do |model|

  model.class.stub!(:find).and_return(true)

  !model.valid? && model.errors.invalid?(attribute)
end

end

But this works (obviously I also define a @valid_attribute hash)

def validate_uniqueness_of(attribute)
return simple_matcher(“model to validate the uniqueness of
#{attribute}”) do |model|

  model.class.create!(@valid_attributes)
  model.nombre = @valid_attributes[:nombre]

  !model.valid? && model.errors.invalid?(attribute)
end

end

And the question.
What issue can be with mocking the find method in the class?
What can I try?

Thanks
Juanma.


#2

Well, it seems tha the error is indeed in the stubbing of the find
method in the class of the model.

def validate_uniqueness_of(attribute)
return simple_matcher(“model to validate the uniqueness of
#{attribute}”) do |model|
model.class.stub!(:find).and_return(true)
!model.valid? && model.errors.invalid?(attribute)
end
end

And I found that it has something to do with the names of the models or
attributes.

I have create two models ‘Book’ and ‘Plano’

script/generate rspec_model Book name:string

script/generate rspec_model Plano nombre:string
#in Spanish, although I have not touched the inflector)

===============================

#book.rb
class Book < ActiveRecord::Base
validates_uniqueness_of :name
end

#book_spec.rb
require File.expand_path(File.dirname(FILE) + ‘/…/spec_helper’)
describe Book do
it do
Book.new.should validate_uniqueness_of(:name)
end
end

=============================

#plano.rb
class Plano < ActiveRecord::Base
validates_uniqueness_of :nombre
end

#plano_spec.rb
require File.expand_path(File.dirname(FILE) + ‘/…/spec_helper’)
describe Plano do
it do
Plano.new.should validate_uniqueness_of(:nombre)
end
end

=======================================

The spec in ‘Book’ pass, but the spec in ‘Plano’ fails

and I even see in test.log that the there is a select query for Plano
and none for Book. The method find for class Plano is not being stubbed.

I think there is a bug!!

Juanma


#3

On Mon, Dec 29, 2008 at 5:04 AM, Juanma C. removed_email_address@domain.invalid
wrote:

t.string “provincia”
before(:each) do

updated_at: nil>
return simple_matcher(“model to validate the uniqueness of
#{attribute}”) do |model|

 model.class.stub!(:find).and_return(true)

 !model.valid? && model.errors.invalid?(attribute)

end
end

I’m not really sure why this is stubbing find, or why the stub value
is true instead of a model. Actually, I don’t even see how this would
specify validating uniqueness of the attribute without very specific
setup:

first = Centro.create(:nombre => “example”)
second = Centro.create(:nombre => “example”)
second.should validate_uniqueness_of(:nombre)

I don’t see any specs for the rspec-on-rails-matchers library on
github, and no activity in 9 months, so I’m guessing that it is
incomplete/no longer being maintained.

Josh K., if you’re reading this, can you respond?

Thanks,
David


#4

David C. wrote:

I’m not really sure why this is stubbing find, or why the stub value
is true instead of a model. Actually, I don’t even see how this would
specify validating uniqueness of the attribute without very specific
setup:

first = Centro.create(:nombre => “example”)
second = Centro.create(:nombre => “example”)
second.should validate_uniqueness_of(:nombre)

I see how it works, I think.
When the matcher calls the ‘valid?’ method in the object, it makes the
call to the find method of the class only if we have specified the
validates_uniqueness_of method in our model, if this return something
then the object is not valid, this is what we are stubbing, no?

But, as I said in a message before, I think the problem is with the
names of the models or the attributes. I can send a tar file with a very
simple app as an attachemnt if you want, that exhibits the problem.

Juanma.


#5

On Mon, Dec 29, 2008 at 7:20 AM, David C. removed_email_address@domain.invalid
wrote:

I don’t see any specs for the rspec-on-rails-matchers library on
github, and no activity in 9 months, so I’m guessing that it is
incomplete/no longer being maintained.

Josh K., if you’re reading this, can you respond?

I unfortunately have let this project take a backseat to everything
else that I’ve been hacking on, which is too bad as I’ve received some
good patches. There are forks out on github which have specs and have
fixed the problem with validate_uniqueness_of.

I’ve been saying for months that I’ll pick it back up, hopefully this
thread can serve as that additional motivator to get me off my ass.


Josh K.
phone: 509-979-1593
email: removed_email_address@domain.invalid
web: http://joshknowles.com


#6

Josh K. wrote:

There are forks out on github which have specs and have
fixed the problem with validate_uniqueness_of.

I have test a plugin with that fixed (from negonicrac) and it still has
the same problem for me.

I see that this plugin already has specs, and want to try them.
But I don’t know how to run specs in a plugin.

I use rake spec:plugins but fails

jmcervera@jmcervera-laptop:~/aaa/vendor$ rake spec:plugins
(in /home/jmcervera/aaa)
./vendor/plugins/rspec-on-rails-matchers/spec/spec_helper.rb:2:in
require': no such file to load -- activerecord (LoadError) from ./vendor/plugins/rspec-on-rails-matchers/spec/spec_helper.rb:2 from ./vendor/plugins/rspec-on-rails-matchers/spec/observers_spec.rb:1:inrequire’
from ./vendor/plugins/rspec-on-rails-matchers/spec/observers_spec.rb:1
from
/usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/runner/example_group_runner.rb:14:in
load' from /usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/runner/example_group_runner.rb:14:inload_files’
from
/usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/runner/example_group_runner.rb:13:in
each' from /usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/runner/example_group_runner.rb:13:inload_files’
from
/usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/runner/options.rb:98:in
run_examples' from /usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/runner/command_line.rb:10:inrun’
from /usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/bin/spec:4
rake aborted!
Command /usr/bin/ruby1.8
-I"/usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib"
“/usr/lib/ruby/gems/1.8/gems/rspec-1.1.11/bin/spec”
“vendor/plugins/rspec-on-rails-matchers/spec/observers_spec.rb”
“vendor/plugins/rspec-on-rails-matchers/spec/validations_spec.rb”
“vendor/plugins/rspec-on-rails-matchers/spec/associations_spec.rb”
“vendor/plugins/rspec-on-rails-matchers/spec/views_spec.rb” --options
“/home/jmcervera/aaa/spec/spec.opts” failed

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

this is the spec_helper.rb file that is failing in line 2

require ‘spec’
require ‘activerecord’

Dir.glob(File.dirname(FILE) +
‘/…/lib/spec/rails/matchers/*.rb’).each do |f|
require f
end

include Spec::Rails::Matchers

How should I require ‘activerecord’?
Or how I have to do the setup for testing/specing plugins?
Any URL for that?

Thanks
Juanma C.