traducir significa qué ingles español ruby-on-rails ruby unit-testing controller devise

ruby-on-rails - ingles - qué significa en español



¿Cómo puedo hacer que Factory Girl NUNCA llegue a la base de datos si llamo a Factory.build para que mis pruebas de controlador sean RÁPIDAS? (2)

Estoy en una búsqueda para hacer que mis pruebas de Rails sean más rápidas. Solo tengo 520 pruebas, pero tardan 62 segundos en ejecutarse en bash y 82 segundos en ejecutarse en Rubymine.

Como ejemplo de una prueba de controlador típica, estaba usando este código para iniciar sesión como @usuario y crear el @comment básico en un controlador de comentarios para mis pruebas de controlador RSpec:

before(:each) do @user = Factory.create(:user) sign_in @user @comment = Factory.create(:comment) end

Como te darás cuenta ... esto es lento. @user un @user , pero también construye las asociaciones para ese usuario. Lo mismo para el @comment .

Así que pensé que llamar a Factory.build(:user) lo resolvería ... pero me salen errores raros. Por ejemplo, current_user devuelve nil .

Entonces ... decidí usar Factory.build() y apagar todos los filtros anteriores en mi controlador principal. Sin embargo, mi registro rspec todavía dice que una TONADA de inserciones están llegando a la base de datos cuando inspecciono el registro RSPec después (¡estamos hablando de cientos de líneas de código para solo 3 pruebas!)

before(:each) do @user = Factory.build(:user) #sign_in @user controller.stub(:authenticate_user!) #before_filter controller.stub(:add_secure_model_data) #before_filter controller.stub(:current_user).and_return(@user) @comment = Factory.build(:comment) end

Lo triste es que el bloque before(:each) tiene un efecto CERO en el rendimiento de la prueba. Como descubrí, llamar a Factory.build() todavía llamará internamente a Factory.create() en las asociaciones secundarias.

Aquí hay un bloque before(:each) que elimina efectivamente la basura producida en el registro de RSpec. Me dio un aumento de rendimiento de prueba de 35-40%

before(:each) do @user = Factory.build(:user, :role => Factory.build(:role)) #sign_in @user controller.stub(:authenticate_user!) controller.stub(:add_secure_model_data) controller.stub(:current_user).and_return(@user) # both of these are still super slow. WTF?! @site_update = Factory.build(:site_update, :id => 5, :author => Factory.build(:user, :role => Factory.build(:role))) @comment = Factory.build(:comment, :author => Factory.build(:user, :role => Factory.build(:role)), :commentable => @site_update) end

Esto hace que las pruebas se ejecuten más rápido, pero también es feo como pecado. No podemos escribir esto seriamente para cada prueba ... ¿verdad? Eso es una locura. No lo haré.

¡También quiero señalar que cualquiera de estas líneas de Factory.build() todavía toma aproximadamente 15 segundos, a pesar de que NO están llegando a la base de datos!

¡Ejecutar solo 3 pruebas todavía resulta en alrededor de .3 a .35 segundos de tiempo ocupado por factory_girl PER test! Creo que eso es totalmente inaceptable. Si elimina las líneas Factory.build() , las pruebas se ejecutan en 0.00001 segundos.

Creo que el jurado está en: factory_girl es una biblioteca muy lenta. ¿Es la única solución para no usarlo?

Aquí están mis factories.rb .

Factory.define :role do |f| f.name "Admin" end Factory.define :user do |f| f.first_name "Banoo" f.last_name "Smith" f.sequence(:email) { |n| "Banoo.Smith#{n}@gmail.com" } f.password "secretpassword" f.association :role end Factory.define :admin do |f| f.first_name "Banoo" f.last_name "Smith" f.sequence(:email) { |n| "admin#{n}@gmail.com" } f.password "secretpassword" f.association :role end Factory.define :course_provider do |f| f.first_name "Josh" f.last_name "Bolson" f.sequence(:email) { |n| "josh.bolson#{n}@gmail.com" } f.password "secretpassword" f.association :role end Factory.define :director do |f| f.first_name "Director" f.last_name "Dude" f.sequence(:email) { |n| "director#{n}@gmail.com" } f.password "secretpassword" f.association :role end Factory.define :instructor do |f| f.first_name "Instructor" f.last_name "Dude" f.sequence(:email) { |n| "instructor#{n}@gmail.com" } f.password "secretpassword" f.association :role end Factory.define :trainee do |f| f.first_name "Trainee" f.last_name "Dude" f.sequence(:email) { |n| "trainee#{n}@gmail.com" } f.password "secretpassword" f.association :role end Factory.define :private_message do |f| f.subject "Subject" f.content "content" f.is_deleted_by_sender false f.association :sender, :factory => :user end Factory.define :recipient do |f| f.is_read false f.is_deleted false f.association :receiver, :factory => :user f.association :private_message end Factory.define :course_template do |f| f.name "name" f.description "description" f.association :course_provider end Factory.define :site_update do |f| f.subject "Subject" f.intro "intro" f.content "content" f.association :author, :factory => :user end Factory.define :comment do |f| f.content "content" f.association :author, :factory => :user f.association :commentable, :factory => :site_update end Factory.define :country do |f| f.name "Liberty" end Factory.define :province do |f| f.name "Freedom" f.association :country end Factory.define :payment_plan do |f| f.name "name" f.monthly_amount 79 f.audience "Enterprises" f.active_courses "500-2000" end Factory.define :company do |f| f.name "name" f.phone_number "455-323-2132" f.address "address" f.postal_code "N7G-5F4" f.association :province f.association :payment_plan end Factory.define :company_user do |f| f.first_name "Dan" f.last_name "Grayson" f.sequence(:email) { |n| "dan.grayson#{n}@gmail.com" } f.password "secretpassword" f.association :role f.association :company end Factory.define :course do |f| f.notes "notes" f.difficulty 100 f.association :course_template f.association :instructor, :factory => :company_user end Factory.define :study_group do |f| f.name "name" end Factory.define :help_category do |f| f.name "name" end Factory.define :help_document do |f| f.question "question" f.content "content" f.association :category, :factory => :help_category end Factory.define :tag do |f| f.name "name" end Factory.define :partial_mapping do |f| f.from_suffix "ing" f.to_suffix "ing" end Factory.define :newsletter do |f| f.subject "subject" f.content "content" end Factory.define :press_contact do |f| f.full_name "Banoo Smith" f.email ''[email protected]'' f.phone_number "455-323-2132" f.address "address" f.postal_code "N9B-3W5" f.association :province end Factory.define :press_release do |f| f.headline "Headline" f.origin "origin" f.intro "intro" f.body "body" f.association :contact, :factory => :press_contact end Factory.define :theme do |f| end

Y referente interesante. Se tarda de .1 a .14 segundos en promedio para hacer una llamada a Factory.create(:user) :

$ rails runner ''Benchmark.bm {|x| x.report { 100.times { Factory.create(:user) } } }'' user system total real 9.940000 0.080000 10.020000 ( 14.872736)

Incluso un Factory.build(:user) toma para siempre ... y esto es con :default_strategy => :build activada!

$ rails runner ''Benchmark.bm {|x| x.report { 100.times { Factory.build(:user) } } }'' user system total real 9.350000 0.030000 9.380000 ( 11.798339)

Claramente, esto es evidencia de que algo está mal con factory_girl. La solución es deshacerse de él o asegurarse de que utiliza Factory.build . Esa es la respuesta.

Ya que básicamente he resuelto mi propio problema, me pregunto por qué Factory_girl es tan popular y por qué es "sabiduría común". Se puede llegar a la conclusión objetiva de que cualquier beneficio que se pueda obtener al usar Factory Girl, y hay muchas cosas buenas al respecto, no vale la pena el costo de rendimiento. Estoy seguro de que se podría desarrollar una mejor gema de fábrica que sea mucho más eficaz ... pero factory_girl desafortunadamente no lo es.

Mi solución a continuación utiliza la creación de instancias y apéndices de objetos básicos, y las pruebas continúan pasando Creo que el uso de Ruby básico, los apéndices y el llenado de los valores de los objetos de forma manual para cada prueba es lo "correcto" que se debe hacer si desea evitar los dispositivos y obtener un alto rendimiento al ejecutar pruebas.


Bueno, supongo que voy a responder mi propia pregunta. Creo que es la respuesta correcta, y tal vez otros puedan aprender de ella, ya que tuve que pasar algunas horas para aprenderla.

Así es como obtuve una mejora de velocidad del 2000% (o 20x):

before(:each) do @user = User.new controller.stub(:authenticate_user!) controller.stub(:current_user).and_return(@user) controller.stub(:add_secure_model_data) @site_update = SiteUpdate.new @comment = Comment.new end

La solución es simplemente no utilizar Fábricas de ningún tipo para las pruebas de los controladores (y quizás otros tipos de pruebas). Sugiero que solo uses Factory cuando sea demasiado doloroso hacer lo contrario.

¡Las 3 pruebas ahora corren en 0.07 segundos! Antes de que fueran 1.4 segundos para ejecutar las 3 pruebas.

Factory_girl es simplemente una biblioteca terriblemente lenta. No sé qué diablos está haciendo, pero no está perfilado correctamente.

Sí, sé que está haciendo mucho más que simples declaraciones de MyClass.new ... pero incluso para un lenguaje de scripts más lento como Ruby, el rendimiento es muchos órdenes de magnitud más lento que la creación de instancias de clase básica. Debe someterse a una optimización masiva para que Factory.build(:my_class) se Factory.build(:my_class) más en línea con MyClass.new

Le sugeriría a los implementadores de Factory_girl que intenten obtenerlo para que su sobrecarga no sea mucho más lenta que una llamada MyClass.new básica (excluyendo la sobrecarga de la base de datos ... eso no se puede evitar). Debería proporcionar una buena forma de construir objetos y no debería tener que pagar una multa de rendimiento de 20x para obtener este beneficio. Eso no es una compensación aceptable.

Todo esto es realmente muy malo, porque Factory.build sería bueno en los controladores cuando tienes render_views activadas dentro de las especificaciones de tu controlador. Debe haber una motivación significativa para corregir esto.

Mientras tanto, solo usa las clases básicas de Ruby / Rails. Creo que te sorprenderás de lo rápido que son ...


Tuve el mismo problema que @FireEmblem y finalmente lo reduje a FactoryGirl.build . FactoryGirl.stub no mejoró las cosas.

Finalmente me di cuenta de que uno de mis modelos tenía una lógica de validación que hacía una solicitud HTTP cuando un campo determinado estaba presente. La fábrica puso un valor en ese campo, por lo que en el exterior, parecía que FactoryGirl estaba desacelerando mis pruebas. En realidad, lo fue, pero solo porque activó la solicitud HTTP. Al eliminar una línea de una de mis fábricas, se eliminó la solicitud HTTP, lo que provocó una mejora del rendimiento 60x.