tutorial rails matchers factory_girl_rails bot ruby-on-rails ruby-on-rails-4 rspec rake rspec3

ruby-on-rails - matchers - rspec rails tutorial



Prueba del Rake en Rails: aumento de errores mĂșltiples silenciados en prueba (3)

¿Intentó pasar el error específico ?:

expect { Rake::Task[task_name].invoke }.to raise_error(StandardError)

Tengo una tarea de rastrillo que protege contra peligrosas rasks de rastrillo Rails, en función del entorno. Funciona bien. Cuando pruebo cada método peligroso individual en RSpec, la prueba pasa. Cuando pruebo múltiples en una fila, para múltiples entornos, la prueba falla después de la primera. Incluso si ejecuto la prueba varias veces por la misma acción peligrosa, rake db:setup por ejemplo, solo pasará la primera vez. Si ejecuto las pruebas como declaraciones individuales, una para cada acción peligrosa, solo las dos primeras pasarán (hay 4).

¿Cómo puedo hacer que RSpec se comporte correctamente aquí, y pasar todas las pruebas cuando se ejecuta en una suite?

La tarea de rake

# guard_dangerous_tasks.rake class InvalidTaskError < StandardError; end task :guard_dangerous_tasks => :environment do unless Rails.env == ''development'' raise InvalidTaskError end end %w[ db:setup db:reset ].each do |task| Rake::Task[task].enhance [''guard_dangerous_tasks''] end

La prueba RSpec

require ''spec_helper'' require ''rake'' load ''Rakefile'' describe ''dangerous_tasks'' do context ''given a production environment'' do it ''prevents dangerous tasks'' do allow(Rails).to receive(:env).and_return(''production'') %w[ db:setup db:reset ].each do |task_name| expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) end end end context ''given a test environment'' do it ''prevents dangerous tasks'' do allow(Rails).to receive(:env).and_return(''test'') %w[ db:setup db:reset ].each do |task_name| expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) end end end end

Salida RSpec

# we know the guard task did its job, # because the rake task didn''t actually run. Failure/Error: expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) expected InvalidTaskError but nothing was raised


Parece que dos tareas no pueden apuntar a la misma tarea para la enhancement por lo que tal vez haya un conflicto en el tiempo de ejecución. Entonces prueba el método de block para manejar la situación.

class InvalidTaskError < StandardError; end %w[ db:setup db:reset ].each do |task| Rake::Task[task].enhance do unless Rails.env == ''development'' raise InvalidTaskError end end end

y en el archivo de especificaciones, la siguiente modificación crearía dos ejemplos para rastrear las especificaciones de manera adecuada.

# require ''rails_helper'' require ''spec_helper'' require ''rake'' load ''Rakefile'' describe ''dangerous_tasks'' do context ''given a production environment'' do %w[ db:setup db:reset ].each do |task_name| it "prevents dangerous tasks #{task_name}" do allow(Rails).to receive(:env).and_return(''production'') expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) end end end end


Puedo pensar en dos soluciones para tu problema.

Pero primero debemos averiguar dónde está la raíz del problema.

Raíz del problema

Comencemos con una línea de su código:

Rake::Task[task].enhance [''guard_dangerous_tasks'']

Comparándolo con el código fuente de Rake::Task

# File rake/task.rb, line 96 def enhance(deps=nil, &block) @prerequisites |= deps if deps @actions << block if block_given? self end

puede ver que guard_dangerous_tasks debe agregarse a @prerequisites array. Se puede verificar fácilmente:

p Rake::Task[''db:reset''].prerequisites # => ["environment", "load_config", "guard_dangerous_tasks"]

Continuando con su código fuente.

Utiliza invoke para ejecutar tareas. Si prestamos mucha atención para invoke la documentación de ''s'', indica:

Invoca la tarea si es necesario .

Una vez que se ejecuta la tarea, no se puede invocar nuevamente (a menos que la volvamos a habilitar).

Pero, ¿por qué debería ser esto un problema? Estamos ejecutando diferentes tareas, ¿verdad? ¡Pero en realidad no lo hacemos!

guard_dangerous_tasks antes de todas las tareas en nuestra matriz de tareas. Y se está ejecutando solo una vez.

La solución n. ° 1 no es la mejor

Tan pronto como sepamos cuál es nuestro problema, podemos pensar en uno (no es la mejor solución).

guard_dangerous_tasks habilitar guard_dangerous_tasks después de cada iteración:

dangerous_task = Rake::Task[''guard_dangerous_tasks''] %w[ db:setup db:reset ].each do |task_name| expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) dangerous_task.reenable end

Solución # 2 guard_dangerous_tasks no es un requisito previo

¡ guard_dangerous_tasks una mejor solución a nuestro problema si nos damos cuenta de que guard_dangerous_tasks no debería ser un requisito previo! Se supone que los requisitos previos para "preparar" la etapa y se ejecuten una sola vez. ¡Pero nunca deberíamos cegar nuestros ojos a los peligros!

Esta es la razón por la que deberíamos extender con guard_dangerous_tasks como una acción, que se ejecutará cada vez que se ejecute la tarea principal.

De acuerdo con el código fuente de Rake::Task (ver arriba) deberíamos pasar nuestra lógica en un bloque si queremos que se agregue como una acción.

%w[ db:setup db:reset ].each do |task| Rake::Task[task].enhance do Rake::Task[''guard_dangerous_tasks''].execute end end

Podemos dejar nuestra prueba sin cambios ahora y pasa:

%w[ db:setup db:reset ].each do |task_name| expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) end

Pero dejar invoke es una entrada para nuevos problemas. Es mejor ser reemplazado por execute :

%w[ db:setup db:reset ].each do |task_name| expect { Rake::Task[task_name].execute }.to raise_error(InvalidTaskError) end

¡Ten cuidado con invoke !

Dijimos más arriba, que usar invoke es un ticket para nuevos problemas. ¿Qué tipo de problemas?

Probemos probar nuestro código para entornos de test y production . Si envolvemos nuestras pruebas dentro de este ciclo:

[''production'',''test''].each do |env_name| env = ActiveSupport::StringInquirer.new(env_name) allow(Rails).to receive(:env).and_return(env) %w[ db:setup db:reset ].each do |task_name| expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError) end end

nuestra prueba fallará con la razón original. Puedes arreglar esto fácilmente al reemplazar la línea

expect { Rake::Task[task_name].invoke }.to raise_error(InvalidTaskError)

con

expect { Rake::Task[task_name].execute }.to raise_error(InvalidTaskError)

Entonces, ¿cuál fue el motivo? Probablemente ya lo adivines.

En la prueba de falla, invocamos las mismas dos tareas dos veces. La primera vez que fueron ejecutados. La segunda vez deberían volver a habilitarse antes de la invocación para su ejecución. Cuando usamos execute , la acción se vuelve a habilitar automáticamente.

Nota Puede encontrar un ejemplo de trabajo de este proyecto aquí: https://github.com/dimakura/-projects/tree/master/31821220-testing-rake