Trying to Overide Class Object Methdos For Testing

Hi,

I thought I had a handle on the whole singleton class thing but now I’m
not too sure.

I have a class definition:

class ValidationMaster
def validate(params)
# complex and time consuming validation
# returns true on success, raises Exception
# on failure
end
end

Okay, so when I’m running my functional tests within rails, I want to be
able to control how the validate(params) method behaves.

So, I’ve created a ValidationMaster class definition and put it in
RAILS_ROOT/test/mocks/test/validation_master.rb

The methods I’ve defined there seem to be correctly overriding those of
the original class definition.

Now here is where I’m having problems. Within certain functional tests,
I want validate(params) to return true. Other times
I want it to fail and throw an exception. Thus, I can’t rely on the
Mock ValidationMaster class definition to take care of this.

But then I thought, HEY, within each test I can open up the singleton
class for the ValidationMaster class object. Whoo hoo,
I’m in charge now!

def test_stuff
class << ValidationMaster
def validate(params)
raise ValidationException
end
end

vm = ValidationMaster.new
vm.validate(“Jeff”)
end

But, when I run my test, the exception is not getting thrown. The
methods I’ve defined in the Mock are all working right, but it’s somehow
not seeing
the override within test_stuff. Am I mistaken here, can I not override
the class definition of ValidationMaster like this?

Thanks,
Steven

On 15/08/06, Steven H. [email protected] wrote:

# on failure

the original class definition.
def test_stuff
But, when I run my test, the exception is not getting thrown. The
methods I’ve defined in the Mock are all working right, but it’s somehow
not seeing
the override within test_stuff. Am I mistaken here, can I not override
the class definition of ValidationMaster like this?

I think this is what you want…

def test_stuff
vm = ValidationMaster.new
class << vm
def validate(params)
raise ValidationException
end
end

vm.validate(“Jeff”)
end

However, you might want to consider using Mocha
http://mocha.rubyforge.orgto write the test more concisely…

def test_stuff
vm = ValidationMaster.new
vm.stubs(:validate).raises(ValidationException)
vm.validate(“Jeff”)
end

Hope that helps.
James.

James M. wrote:

# returns true on success, raises Exception

The methods I’ve defined there seem to be correctly overriding those of

vm = ValidationMaster.new
http://mocha.rubyforge.orgto write the test more concisely…



Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

I would like to redefine a method at the class object level. Thus any
new instances of the ValidationMaster object would have a new definition
for the validate(params) method. What you are doing is changing a
single instance of the ValidationMaster object.

Mocha looks pretty cool, however I’m still a bit new to the whole
testing thing so I’d like to get a bit better at it before moving on
to something like Mocha.

Thanks,
Steven

Steven H. wrote:

# complex and time consuming validation

I’m in charge now!
end
def test_stuff
However, you might want to consider using Mocha
http://blog.floehopper.org
I would like to redefine a method at the class object level. Thus any


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

Ok, I think I see where I’m going wrong here.

Doing:

class << ValidationMaster
end

allows me to add class level methods.

So if I had

class ValidationMaster
def validate()
end
end

and then I did

class << ValidationMaster
def validate()
end
end

I would essentially have two validiate() methods in the ValidationMaster
class. It would be like having this definition:

class ValidationMaster
def validate()
puts “one”
end

def self.validate()
puts “two”
end
end

vm = ValidationMaster.new
vm.validate() #=> “one”
ValidationMaster.validate() #=> “two”

-Steven

James M. wrote:

first definition (perhaps in another file)

class ValidationMaster

to something like Mocha.


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

Ok, this does what I was trying to accomplish:

class ValidationMaster
def validate(params)
# complex and time consuming validation
# returns true on success, raises Exception
# on failure
end
end

def test_validation_fails
ValidationMaster.class_eval { def validate(params); raise Exception;
end }

post(:download, opts)
assert_response(:redirect)
assert_equal(flash[:error], “Authentication failed: token
verification failed”)
end

def test_validation_succeeds
ValidationMaster.class_eval { def validate(params); return true; end
}
post(:download, opts)
assert_response(:success)
assert_equal(flash[:error], nil)
end

I don’t want the actual validation to run, I just want a specific result
from this method. The result I want differs between tests. Now I can
test my controller’s actions without having to have the “real”
validation() method executed. Sorry for not giving a better explanation
of what I was trying to do.

Thanks,
Steven

On 15/08/06, Steven H. [email protected] wrote:

def test_validation_succeeds
validation() method executed. Sorry for not giving a better explanation
of what I was trying to do.

That does work, but watch out for the gotcha that your method
re-definition
is not local to the test. So depending on which was the last of these to
run, the behaviour in other tests might not be what you expect. This is
one
of the benefits of Mocha, which restores the original implementation
after
each test (in a secret teardown). Your tests would become…

def test_validation_fails
ValidationMaster.any_instance.stubs(:validate).raises(Exception)
post(:download, opts)
assert_response(:redirect)
assert_equal(flash[:error], “Authentication failed: token
verification
failed”)
end

def test_validation_succeeds
ValidationMaster.any_instance.stubs(:validate).returns(true)
post(:download, opts)
assert_response(:success)
assert_equal(flash[:error], nil)
end

James.

James M. wrote:

end

test my controller’s actions without having to have the “real”
def test_validation_fails
assert_response(:success)
Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

“That does work, but watch out for the gotcha that your method
re-definition is not local to the test.”

Heh, I was just about to email the list again asking about this.

“This is one of the benefits of Mocha, which restores the original
implementation after each test (in a secret teardown).”

I might using Mocha sooner than I expected.

Thanks,
Steven

On 15/08/06, Steven H. [email protected] wrote:

I would like to redefine a method at the class object level. Thus any
new instances of the ValidationMaster object would have a new definition
for the validate(params) method. What you are doing is changing a
single instance of the ValidationMaster object.

You can just re-open the class and redefine the method…

first definition (perhaps in another file)

class ValidationMaster
def validate()
puts “one”
end
end

vm = ValidationMaster.new
vm.validate # => “one”

second definition

class ValidationMaster
def validate()
puts “two”
end
end

vm = ValidationMaster.new
vm.validate # => “two”

Mocha looks pretty cool, however I’m still a bit new to the whole

testing thing so I’d like to get a bit better at it before moving on
to something like Mocha.

No worries.

James.