El ejemplo frecuente que se utiliza para mostrar el beneficio de usar Mock Objects durante el testing de nuestro software, es el caso en el que la aplicación que estamos desarrollando depende de un ente externo que no está disponible durante la fase de desarrollo/testing, por ejemplo nuestro software debe interactuar con un ERP (SAP, Baan, etc), y no tenemos el ERP a nuestra disposición. En este caso lo que se hace es crear un mock object que reemplaza el ERP (a momento de testing) , para poder probar asi la funcionalidad de nuestro software.

A pesar de que el ejemplo "frecuente" es válido, hay situaciones más comúnes que tambien justifican el uso de mock objects.

Supongamos que nuestro software es una aplicación Web (hecha en RubyOnRails) que tiene la funcionalidad de autenticar un usuario vía un cookie (remember-me feature), y que dicho cookie tiene una fecha de expiración, despues de la cual no es válido para autenticar un usuario en nuestra aplicación.

Dado esto se quiere probar que la expiración del cookie efectivamente funcione (del lado de nuestra aplicación, no del lado del browser). Es decir, tenemos que simular el paso del tiempo (para alcanzar que la fecha de expiración)

Para este functional test tenemos los siguientes archivos: /test/functional/user_controller_test.rb (suponiendo que el controller encargado de la autenticación es el user_controller.rb) y /test/mocks/test/timer.rb

Nuestro /test/functional/user_controller_test.rb sería algo de este estilo:

RUBY:
  1. require File.dirname(__FILE__) + '/../test_helper'
  2. require 'user_controller'
  3.  
  4. # Re-raise errors caught by the controller.
  5. class UserController; def rescue_action(e) raise e end; end
  6.  
  7. class UserControllerTest <Test::Unit::TestCase
  8.   fixtures :users
  9.  
  10.   def setup
  11.     @controller = UserController.new
  12.     @request    = ActionController::TestRequest.new
  13.     @response   = ActionController::TestResponse.new
  14.   end
  15.  
  16.   def test_login_cookie_expired
  17.     # go to a secure page with a valid value cookie but already expired
  18.     @request.cookies['remember'] = CGI::Cookie.new('remember', 'valid_value')
  19.     Time.advance_by_days = APP_CONFIG[:cookie_login_expires]
  20.     get :secure_page
  21.     assert_redirected_to :action => 'login'
  22.     Time.advance_by_days = 0
  23.   end
  24. end

El final del método test_login_cookie_expired es el que hace la prueba de la expiración del cookie, para esto lo que hacemos es modificar la clase Time, en particular el método now y le agregamos el atributo advance_by_days a la clase (no a las instancias), vía un mock object (/test/mocks/test/timer.rb) para lograr simular el "avance del tiempo".

RUBY:
  1. require 'time'
  2.  
  3. Time.class_eval {
  4.   @@advance_by_days = 0
  5.   cattr_accessor :advance_by_days
  6.  
  7.   class << Time
  8.     #> Este alias permite conservar el método original
  9.     alias now_old now
  10.     #> Aquí se redefine el método "now"
  11.     def now
  12.       if Time.advance_by_days != 0
  13.         return Time.at(now_old.to_i + Time.advance_by_days * 60 * 60 * 24 + 1)
  14.       else
  15.         now_old
  16.       end
  17.     end
  18.   end
  19. }

El archivo /test/mocks/test/timer.rb sería:

Esta modificación a la clase Time funciona (y en general los mock objects), porque Rails modifica el search path para incluir de primero el path de los mocks ( /test/mocks/test ).

La idea de modificar la clase Time fue tomada del SaltedHashLoginGenerator

"A language that doesn't affect the way you think about programming, is not worth knowing."

Alan J. Perlis


0 Respuestas a “Usando Mock Objects en Rails”

  1. Ningún Comentario

Añade un Comentario





RSS feeds

Suscríbete a nuestros RSS Feeds