Tests funcionales con Ruby on Rails

Actualmente nos encontramos en un punto en el que todavía no tenemos una primera maquetación de la interfaz de usuario de flatee, pero de todas formas estamos desarrollando.

¿Cómo lo hacemos?. Bien, estamos desarrollando con la ayuda de test funcionales para comprobar que todo lo que hacemos está correcto. Además estos tests nos servirán para comprobar que no se rompe nada con futuras modificaciones, y si se rompe ver que es lo que hemos tocado más de la cuenta.

Ruby on Rails nos trae de serie la posibilidad de crear test funcionales, verificando las acciones de nuestros controladores. Cada vez que generamos un controlador, se nos crea en el mismo momento una clase en [nombre_app]/test/functional/[mi_controller]_test.rb, donde podremos definir nuestras pruebas. Esa clase hereda de ActionController::TestCase, y en ella utilizaremos implementaciones para test de request y response, y haremos peticiones HTTP (get, post, put, head y delete) pudiendo pasar parámetros, comparando los resultados de esas llamadas con assertions,etc.

Por otro lado, tenemos los fixtures, que se crean al generar las clases modelo. Los fixtures, por defecto, son unos ficheros con formato YAML donde introducimos datos de prueba a los que nos referiremos en nuestros tests. Como es de imaginar los fixtures se pueden utilizar también en test unitarios.

Una vez explicado esto, veamos como es la práctica. En nuestro caso tenemos un modelo piso con ciudad y precio; un fixture de pisos; y un pisos_controller con las acciones listado y crear.

Este podría ser nuestro fixture(nombreapp/test/fixtures/piso.yml):

    piso_madrid:
      id: 1
      ciudad: 'Madrid'
      precio: 350

Nuestras acciones de pisos_controller.rb:

    def listado
      @pisos = Piso.find(:all)
    end
    def crear
      @piso = Piso.new(params[:piso])
      respond_to do |format|
        flash[:notice] = ‘Piso creado correctamente.’
        format.html { redirect_to piso_path(@piso) }
      end
    end

Y ahora vamos a escribir el test pisos_controller_test.rb: Requerimos el controlador que vamos a testear

    require 'pisos_controller'

Definimos qué fixtures utilizaremos, en nuestro caso sólo uno:

    fixtures :pisos

Hacemos el setup con las implementaciones para testing de request y response, además decimos qué controller vamos a utilizar:

    def setup
      @controller = PisosController.new
      @request = ActionController::TestRequest.new
      @response = ActionController::TestResponse.new
    end

Y los tests:

    def test_listado
      #Peticion get al listado
      get :listado
      #Comprobamos que el @pisos del listado, que viene a ser assigns(:pisos), no sea nulo
      assert_not_nil assigns(:pisos)
      #Debe haber un piso, es el que se crea con el fixture
      assert_equal assigns(:pisos).size,1
    end
    def test_crear
      #Peticion post al crear con parámetros
      post :crear, :piso=>{:ciudad=>'Cuatrecorz',:precio=>100}
      #Comprobamos que los valores insertados sean correctos
      assert_equal assigns(:piso).ciudad,'Cuatrecorz'
      assert_equal assigns(:piso).precio,100
      #Comprobamos también la redirección
      assert_redirected_to piso_path(assigns(:piso))
    end

Cuando ejecutemos el test, podremos ver si nuestros controladores se están comportando de manera adecuada y lo que es más interesante aún… podremos ejecutarlos de manera continua a lo largo de la vida del proyecto para evitar que cambios futuros puedan introducir nuevos errores.

La experiencia de los tests esta siendo muy interesante y estamos aprendiendo como hacer nuestro software más robusto: ¡os animamos a que probéis a testar vuestro aplicaciones si es que todavía no lo hacéis!.

Implementando la gestión de usuarios

Sin lugar a dudas, Dani ya os puso sobre la pista de nuestra idea de la gestión de usuarios en cuanto a Flatee. Y de qué manera era necesario tenerla. De tal forma que no voy a entrar en esto, sino más bien en cómo la estamos implementando.

Siguiendo el principio DRY, hemos utilizado el ya ampliamente conocido plugin restful_authentication. Desde hace algún tiempo este plugin se encuentra alojado en github, lo que ha servido para que algunos miembros del equipo trabajen con git, un añadido más.

Nuestra primera misión fue instalar git en nuestras máquinas para poder funcionar con él. En mi caso, ha sido bastante sencillo hay disponible una imagen para instalar en Mac OS X, por lo que la instalación ha sido un click detrás de otro, un simple reinicio del terminal y funcionando.

Luego para descargar el plugin desde github con git, nos basta con:

git clone git://github.com/technoweenie/restful-authentication.git vendor/plugins/restful-authentication

Por otro lado al descargar la versión de restful_authentication, dado que es la última sufrimos algunos problemas, que os queremos detallar.

Lo fundamentarl ahora es generar con el plugin nuestra cuenta de usuario:

./script/generate authenticated user sessions --include-activation --stateful --rspec

las opciones que incluimos detalladas nos dan:

  • include-activation: con esto se generará un ActionMailer que nos permitirá enviar el mail de activación a los usuairos implicados.

  • stateful: da soporte al plugin: acts_as_state_machine que generara el código de activación.

  • rspec: Genera test Rspec y Stories en lugar de los tradicionales test de rails.

Existen más posibilidades, sin embargo para nosotros estas eran las necesarias.

Tras ejecutar esto, el plugin nos recomienda una serie de pasos a seguir, el primero de ellos, debemos añadir un observer al config/environment.rb:

config.active_record.observers = :user_observer

Lo siguiente es instalar acts_as_state_machine, para ello:

svn export http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk vendor/plugins/acts_as_state_machine

Debemos añadir las siguientes rutas a config/routes.rb:

map.signup '/signup', :controller => 'users', :action => 'new'
map.login  '/login',  :controller => 'sessions', :action => 'new'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate', :activation_code => nil

y modificar la existente creada por el plugin de usuarios:

map.resources :users, :member => { :suspend => :put, :unsuspend => :put, :purge => :delete }

Al modelo de usuario hay que añadirle los estados que va a utilizar el plugin acts_as_state_machine:

acts_as_state_machine :initial => :pending
state :passive
state :pending, :enter => :make_activation_code
state :active,  :enter => :do_activate
state :suspended
state :deleted, :enter => :do_delete

Como nota importante, decir que tuvimos que añadir unas líneas al init.rb del plugin, por unos errores que obteníamos de métodos ‘undefined’:

require File.dirname(FILE) + ‘/lib/authorization’
require File.dirname(FILE) + ‘/lib/authorization/stateful_roles’

Tras esto enviamos un mail al autor del plugin, por lo que consideramos es un error para que pudiese incluirlo en el repositorio y quedase corregido.

Registrar usuarios o no registrarlos

Una discusión que hemos tenido ha estado relacionado con el registro de usuarios. Por un lado pretendemos que flatee sea un servicio que llegue al máximo de gente posible, y por otro queremos que se gane calidad en los contactos entre las personas que ponen el anuncio y las que están buscando habitación, ya que se está eligiendo nada menos con quién compartir una vivienda durante una temporada.

Para llegar al máximo de gente posible, lo mejor sería no tener registro de usuarios, confirmar simplemente la dirección de email de quien anuncia y que los contactos se hagan fuera de flatee, por esto la calidad sería más complicado de mejorar. Además surge algún problema incómodo para el usuario, en todas las acciones administrativas hay que ir confirmando la dirección de email (actualizar, eliminar, históricos…).

El obligar a registrarse a todo el mundo significa poner también una barrera de entrada. Quien busca piso tiene muchos sitios parecidos para ver anuncios y elegir con cuáles quiere contactar; mientras que para quién pone el anuncio, es aceptable el registro por la idea de que a más visto sea su anuncio habrán más interesados y más posibilidades de que alguien coincida con el tipo de persona que se busca.

Finalmente nuestra conclusión ha sido hacer algo intermedio. Quien anuncia debe registrarse, pidiéndole lo necesario, y quien busca no está obligado a registrarse simplemente por ver anuncios. Eso no se aleja de cómo funcionan ya algunas webs de clasificados, el añadido más importante está en que cualquier usuario que se registre pueda detallar su perfil, que es lo que aumenta la calidad en los contactos, y poder ver cómo es una persona con la que se puede acabar conviviendo.

De cualquier forma, aunque la entrevista en persona habrá que hacerla siempre, de esta manera se puede conseguir un filtro importante y ahorrar largas caminatas o maratones de entrevistas .

Respecto al comentario que nos hizo RuGI en su momento, no creemos que un sistema de reputación basándonos en la información de otros lugares o propia aportase demasiado, al estar refiriéndonos a la personalidad o modo de vida de una persona, no es algo medible. De todas formas, está contemplado el que si una persona quiere, pueda reflejar sus actividades online y offline para dejarse conocer mejor.

Liberar el código de Flatee

YAVisitor en nuestra entrada de bienvenida, nos sugiere liberar el código de flatee. La verdad es que la propuesta ha llegado demasiado temprano dentro de nuestras labores y en nuestras conversaciones no nos habíamos planteado esta opción.

Tanto nosotros como Linking Paths sabemos lo que es liberar código y participamos del movimiento open source. La lista de iniciativas que hemos creado o en las que participamos activamente es larga:

  • Casi todos hemos trabajado en JavaHispano, una comunidad que aboga por el open source y que es un recurso indispensable de noticias y artículos dentro del mundo java. De hecho, es la comunidad java de habla hispana más grande del mundo.

  • Proyectos open source de todo tipo: cáñamo, licurgo, belegost, jLibrary, …

  • Incluso en estos momentos estamos implicados en el desarrollo de proyectos basados en Tog, la plataforma de redes sociales, que en breve verá la luz y que desde el principio fue concebida como open source).

  • Por último, pero no menos importante, mi compañero Dani participa en estos momentos en el Google Summer of Code, tratando de crear un plugin para Grails, el cual está bajo licencia Apache, o sea libre.

flatee nace, sin dudarlo, con intención de convertirse en el servicio de alquiler de pisos compartidos referente en el mercado latino.

Si analizamos los proyectos open source de mayor éxito veremos que la gran mayoría son productos y herramientas más o menos genéricas capaces de albergar un comunidad de desarrolladores. Cada miembro de la misma puede utilizar y adaptar el software para sus propios proyectos y servicios. Las mejoras surgidas de esa adaptación pueden revertirse a la comunidad y cerrar el ciclo. Ese es el flujo que normalmente acontece en los proyectos open source y, francamente, no creemos que flatee sea un caso similar.

Sin embargo, hay otro foco de creación de proyectos open source que tiene su origen en las mejoras que acabamos de citar. Cuando estas son de un volumen respetable o forman un conjunto lógico lo suficientemente grande son encapsuladas de diferentes maneras: librerías, plugins, gemas, etc. Por ahí sí que podríamos encontrarnos con cosas liberadas bajo el paraguas de flatee, tal y como ya hemos hecho en el pasado, dado que son piezas que podríamos considerar reutilizables y beneficiosas para otros.

Finalmente y como ya hemos comentado, tenemos la intención de ir relatando los problemas con los que nos encontremos a nivel técnico dentro del desarrollo, lo cual hace que se pueda aprender de nuestra experiencia a la vez que podáis orientarnos entorno a determinados problemas que puedan surgir.

¿Por qué una web para compartir piso?

La idea surgió de una necesidad propia, lo tenía como idea/sideproject personal pendiente desde hace aproximadamente un año, que fué la última vez que busqué compañeros de piso, para lo que no había conseguido tiempo para dedicarle. Lo comenté como una posibilidad para desarrollar en el internship junto con otras que estuvimos viendo entre todos. Gracias a otros puntos de vista la idea ha tomado un enfoque distinto, sin perder la esencia original.

La última búsqueda de compañeros la realicé a traves de una web de clasificados genérica que funciona a nivel local (en Zaragoza), que tiene un tráfico bastante alto y no precisa registro de usuarios pero que a mi modo de ver, presenta bastantes limitaciones, esto me llevó a recibir demasiadas llamadas y emails. Me supuso un nivel de estrés y de pérdida de tiempo realmente alto, durante varios días no dejaba de tener llamadas y visitas. Llegando incluso 15 días después de tener las habitaciones alquiladas seguir recibiendo llamadas. Por otro lado en muchos casos en el momento de la visita/entrevista no le encajaba a quien venía a verlo o no me encajaba a mi esa persona.

De todas formas, desde el punto de vista del anunciante se puede considerar un mal menor el que ocurra esto si finalmente se consigue ocupar el piso. Pero hay otras muchas ocasiones dónde el anuncio es poco explicativo o no tiene suficiente detalle de cómo es el piso/habitaciones, ¿llamarías viendo un anuncio del tipo “Alquilo habitación céntrica, en buen estado y bien iluminada. 250€” entre otros muchos anuncios?, este tipo de anuncios suele ser de personas que no tienen muy claro qué deberían poner y se podría solucionar llevando de la mano al usuario. Así todos ganaríamos en tiempo invertido tanto en la búsqueda de compañeros como en la búsqueda de esa habitación que necesitamos.

Desde el punto de vista de quien busca un piso (que también me ha tocado hacer) que se pasea por la ciudad, hace las llamadas, compara pisos; necesita cierto nivel de detalle en los anuncios: desde alguna foto para hacerse una idea, saber de qué dispone el piso, qué tipo de persona es la buscada, dónde está localizado… para hacer el primer corte y ahorrarse caminatas o llamadas de pisos que no se ajustan.

Estas son algunas de las cosas que queremos solucionar con flatee, para mejorar la experiencia tanto de la búsqueda de piso como de nuevos compañeros.

Empezamos con flatee

En primer lugar, bienvenidos a nuestro blog, y en segundo, nos gustaría responder a una simple cuestión: ¿Qué es flatee? De momento flatee es una idea que está poniendose en marcha. Pretendemos ser una web de clasificados especializada en la búsqueda de pisos compartidos, desarrollada como parte del Internship que estamos haciendo dentro de Linking Paths.

La idea de flatee es darle una vuelta a las webs de clasificados para compartir piso: las webs especializadas están congeladas desde hace mucho tiempo, las generales de inmobiliarias a las que se les nota esa generalidad y por último las generales de clasificados que como se puede entender aportan bastante poco. De todas formas, sabemos que nuestra apuesta por la singularidad compite abiertamente en un mercado tradicional. No será fácil, pero el internship no es sólo desarrollo de software sino también hacerse valer en un sector determinado y estudiar vías de negocio.

Como parte de nuestra experiencia en esta aventura, queremos hacer público todo lo que nos acontezca. Esto quiere decir: la evolución del proyecto, los problemas encontrados por el camino, alguna recipe técnica, etc. Todo a través de este blog, que esperamos sea la puerta para establecer el contacto. De momento estamos desarrollando, aún así desde el primer momento nos gustaría recibir vuestro feedback, intercambiar ideas, vuestras aportaciones, todo hasta que podamos liberar versión y podáis empezar a utilizar el portal.

En cuanto a la parte técnica, hemos decidido utilizar Ruby on Rails como framework de desarrollo, del que por supuesto también hablaremos por aquí.

Para los que no nos conozcáis somos: Daniel Latorre y Jesús Navarrete, en breve nos presentaremos con más detalle. De momento tomen asiento y compartan con nosotros esta aventura… si les place! XD