Skip to content

Instantly share code, notes, and snippets.

@javierav
Created August 17, 2020 07:28
Show Gist options
  • Select an option

  • Save javierav/42af04101e9d2884303f63bbeb1f2fc7 to your computer and use it in GitHub Desktop.

Select an option

Save javierav/42af04101e9d2884303f63bbeb1f2fc7 to your computer and use it in GitHub Desktop.
Cómo testear nuestra aplicación

Si has tenido la enorme suerte de trabajar en un proyecto en el que se usa Rails de la manera tradicional (dónde las páginas HTML se renderizan en el servidor y la carga de Javascript es la mínima indispensable), aquí tienes una breve guía de cómo debes testear tu aplicación para conseguir una cobertura y velocidad de ejecución óptimas.

Tipos de tests

Todas las aplicaciones que realicemos deberán implementar los siguientes tests (siempre que sea posible):

Tests unitarios

Es la única parte que no cambia respecto a lo que ya veníamos haciendo. Deberemos testear de forma unitaria los modelos, los jobs, las policies y las clases propias usando la forma habitual.

Recomedaciones

  • Evita persistir los modelos en la base de datos salvo que sea necesario. Si usas FactoryBot para generar modelos, intenta utilizar build en lugar de create siempre que te sea posible.

Tests de sistema (integración)

Con la llegada de Rails 5.1 se mejoró todo el proceso de testeo y el Core Team de Rails decidió introducir un nuevo tipo de test: los tests del sistema (system tests). Estos tests están pensados para testear la interacción del usuario a través del navegador.

Estos tests testean desde el principio al final un determinado flujo dentro de nuestra aplicación, verificando que todos los componentes de nuestra página funcionan correctamente. No debemos testear todos los casos ni los casos raros, ya que este tipo de tests son más costosos en tiempo de ejecución que los demás.

Básicamente es lo mismo que ya teníamos desde hace años en RSpec con los tests de features usando Capybara pero con la principal diferencia de que el driver que controla el navegador se ejecuta en el mismo thread que el servidor de Rails, por lo que la conexión a la base de datos se comparte y por tanto se elimina la necesidad de usar gemas como DatabaseCleaner y la necesidad de borrar e inicializar la base de datos en cada prueba, permitiendo el uso de transacciones y acelerando con ello la velocidad de ejecución de los tests.

Adicionalmente estos tests ya vienen preconfigurados para detectar y usar Capybara, por lo que no tendremos que realizar configuración adicional alguna para que funcione out of the box.

Estos tests se definen en la ruta spec/system tal y como se explica en la documentación oficial.

Aunque sean mas veloces que los tradicionales, siempre testearemos con estos tests los flujos principales de la aplicación, delegando en los tests de requests todas las comprobaciones de permisos o flujos especiales.

Tipos de drivers

Cuando ejecutamos nuestros tests para simular la interacción del usuario, Capybara debe usar lo que se conoce como driver, que es lo que le permite comunicarse con un entorno de ejecución que se encargará de renderizar el contenido de nuestra aplicación y realizar las acciones que nosotros le indiquemos.

Por defecto Capybara usa un driver llamado :rack_test que permite interactuar con el HTML de nuestra página para aplicar selectores y comprobar el contenido de los elementos y que se ejecuta de manera muy rápida (ya que no usa un navegador externo). A cambio este driver no puede ejecutar Javascript, por lo que sólo lo podremos usar en aquellas páginas en las que no tengamos que verificar ninguna interacción que requiera Javascript.

En cambio, si queremos realizar comprobaciones que necesitan ejecutar código Javascript, deberemos usar un driver que se ejecute en un navegador. Para ello Capybara dispone del driver :selenium que implementa un protocolo para abrir y realizar las acciones sobre un navegador, ya sea Google Chrome o Firefox.

Como ejemplo, esta podría ser una configuración de RSpec para ejecutar nuestros tests de sistema usando diferentes drivers en función de lo que vamos a testear necesita ejecutar código Javascript o no:

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :rack_test
  end

  config.before(:each, type: :system, js: true) do
    driven_by :selenium, using: :headless_chrome, screen_size: [1920, 1080] do |driver_option|
      driver_option.add_argument('--no-sandbox')
    end
  end

  config.define_derived_metadata(file_path: /spec\/system/) do |metadata|
    metadata[:browser] = true
  end

  config.filter_run_excluding browser: true # to execute system tests must run rspec -t browser
end

Recomedaciones

  • Siempre que podamos evitaremos el uso de it específicos para cada prueba y usaremos en su lugar un único it que abarque los máximos flujos posibles (principales o de error).

  • Evitaremos iniciar sesión mediante la interfaz (formulario de login), usando stubs en el controlador para que devuelva automáticamente el usuario autenticado.

Tests de requests

Los tests de tipo request nos permiten testear nuestra aplicación pasando por todo el stack de una petición, incluyendo el router, los middleware de rack y nuestro controlador, siendo mucho más realista que el testeo individual de cada controlador como ocurría en los test de controlador. Debido a la mayor cobertura del código, es la nueva forma preferida.

Usaremos estos tests para comprobar, por cada controlador:

  • El código de respuesta HTTP.
  • El contenido de la página es correcto.
  • Si se aplica alguna redirección o no.

Ya no es necesario comprobar las variables de isntancia asignadas o si se renderiza una vista concreta, ya que lo que nos interesa es el resultado de la página renderizada.

Para comprobar el contenido de la página podemos aplicar dos técnicas:

  • Usar los matchers de Capybara como have_content, que aunque no vienen incluídos por defecto en los tests de tipo request, podemos incluirlos nosotros. Es la forma preferida por disponer de más formas de comprobar el contenido y hacer uso de selectores CSS.
# spec/support/capybara_matchers.rb
RSpec.configure do |config|
  config.include Capybara::RSpecMatchers, type: :request
end
# spec/requests/dashboard_spec.rb
it { expect(response.body).to have_content('Lorem ipsum') }
  • Usar el matcher include para comprobar el contenido en el test.
# spec/requests/dashboard_spec.rb
it { expect(response.body).to include('Lorem ipsum') }

Bibliografía

Una colección de enlaces donde puedes profundizar más en el cambio en la forma de testear en Rails:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment