rails captcha and testing using mock objects

By manik July 21, 2006

To prevent bots from Signing up on our application, we added a captcha to our User model. We used the validates_captcha plugin available at http://svn.2750flesk.com/validates_captcha/trunk

The plugin, selects text from a String array for the captcha challenges, so, Sur, my co-programmer, hacked the plugin a little to add random text and improved images.

After adding the plugin we realized that all our tests which validate the User model had started failing. Programmatcially a test case or a bot are not much different, they are both scripts.

Mocks to the rescue.

Here is what I wrote in a file named add_captcha_to_active_record.rb under test/mocks/test directory.

require File.expand_path(File.dirname(__FILE__) +
"/../../../vendor/plugins/validate_captcha/lib/add_captcha_to_active_record")

module AngryMidgetPluginsInc #:nodoc:

	module Validations #:nodoc:

		# module Captcha
		module Captcha #:nodoc:

			# module InstanceMethods
			module InstanceMethods #:nodoc:

			private

				def validate_captcha(options = {}) #:nodoc:

				end

			end

		end#module Captcha

	end#module Validations

end#module AngryMidgetPluginsInc

What I have done by adding this file is, I have asked the test scripts to use the validates_captcha method in /test/mocks/test/add_captcha_to_active_record.rb instead of the validates_captcha method in plugins/validate_captcha/lib/add_captcha_to_active_record.rb

Well actually Rails does all the magic, I just need to give the same file name as the one I want to mock and then define the method that I want to override.

The original validates_captcha method checks that the text entered on the signup screen is the same as that stored on the server. If these do not match it adds a validation error to the base class, the User class in our case.
In the mock validates_captcha method we just do nothing. So a validation error will never be added to the base class.

And now our tests are running and passing again.

I also noted the presence of a directory /test/mocks/development/ … well that means I can even mock classes in the development environment.
One of our application, connects to Paypal to make a payment and then returns back. During development we had commented out this code so that we are not sent to paypal everytime. Now I know how I can avoid commenting or changing the code by using mock objects.
I will be working on that soon and blog about my experiences here.

Share this:

Leave a comment

Your email address will not be published. Required fields are marked *

2 comments

  1. chao lam says:

    Thanks for an informative article about the use of mocks. I ran into exactly the same problem with testing the validates_captcha plugin. My solution was to the :if clause e.g.
    validates_captcha :if => Proc.new {|u| ENV[‘RAILS_ENV’] != ‘test’}

    That seems to work too.
    Ideally, I would really like to have a test case that really validates that the captcha itself works. I wonder what would be the easiest way to do that.

    Again, thanks for sharing,
    chao

  2. Joe Slag says:

    Looks like the plugin developers have added the RAILS_ENV test themselves (in add_captcha_to_active_record.validate_catchpa)