tutorial rails factorybot example bot ruby-on-rails unit-testing rspec factory-bot

ruby on rails - rails - Agilización de asociaciones en las especificaciones del modelo con FactoryGirl-crear vs compilación vs compilación_estimular



rspec factory bot (4)

Si no desea que sus pruebas lleguen a la base de datos, esto es lo que tendría que hacer.

before do @user = FactoryGirl.build_stubbed :user @post = FactoryGirl.build_stubbed :post @user.stub(:posts).and_return([@post]) @post.stub(:user).and_return(@user) end

Nota: Tenga cuidado al usar before(:all) . No se ejecuta en una transacción. Entonces, cualquier cosa que cree before(:all) quedará atrás en la base de datos y podría causar conflicto con otras pruebas

Acerca de FactoryGirl.build , construye el objeto, pero crea las asociaciones.

Por ejemplo:

factory :user do association posts end FactoryGirl.build(:user) #this creates posts in the database even though you are only building the parent object(user)

Digamos que tengo modelos de User y Post , un usuario tiene has_many publicaciones y una publicación belongs_to un usuario.

Cuando escribo una especificación para Post , mi primer instinto es escribir algo como esto:

before do @user = FactoryGirl.create :user @post = @user.posts.new(title: "Foo", content: "bar) end ... tests for @post go here ...

Pero esto creará un nuevo usuario, que accederá a la base de datos, para cada prueba, lo que ralentizará las cosas. ¿Hay una forma mejor de hacer esto que acelerará mis pruebas y evitar golpear el DB tan a menudo?

Según tengo entendido, no puedo usar FactoryGirl.build :user porque, aunque no llegue al DB, las asociaciones no funcionarán correctamente porque @user no tendrá una ID y por lo tanto @post.user ganó no funciona (devuelve nada)

Podría usar FactoryGirl.build_stubbed :user que creó un @post.user FactoryGirl.build_stubbed :user "falso persistente" que tiene una ID, pero @post.user aún devuelve nil. ¿ build_stubbed tiene alguna ventaja práctica sobre build cuando estoy probando cosas relacionadas con asociaciones?

Supongo que podría usar build_stubbed stub @post.user para que devuelva @user ... ¿hay alguna razón por la que esta sea una mala idea?

¿O debería usar create y aceptar el golpe de velocidad?

La única alternativa que se me ocurre sería configurar @user en un bloque before(:all) que parece una mala idea.

¿Cuál es la mejor manera de escribir este tipo de pruebas de una manera limpia y concisa que evite hacer demasiadas consultas DB?


Respuesta corta

@user = FactoryGirl.build_stubbed(:user) @post = FactoryGirl.build_stubbed(:post, :user => @user)

Esto hará que @ post.user funcione sin golpear la base de datos.

Respuesta larga

Mi recomendación sería esperar en el bloque before hasta que esté seguro de que lo necesita. En su lugar, cree los datos que necesita para cada prueba individual y extraiga la duplicación en métodos o fábricas nuevas a medida que lo encuentre.

Además, ¿realmente necesita hacer referencia al usuario en cada prueba individual? Tener @user disponible en cada prueba le dice a otros desarrolladores que es importante en todas partes.

Por último, suponiendo que la asociación de usuarios también se declare en la fábrica de correos, obtendrás automáticamente un post.user funcionamiento cuando post.user build_stubbed(:post) .


Puede ser fácil olvidar las diferencias entre create , build y build_stubbed . Aquí hay una referencia rápida para quienes se encuentran en la misma situación (ya que esta página tiene una posición muy alta en los resultados de búsqueda).

# Returns a User instance that''s not saved (does not write to DB) user = build(:user) # Returns a saved User instance (writes to DB) user = create(:user) # Returns a hash of attributes that can be used to build a User instance attrs = attributes_for(:user) # Returns an object with all defined attributes stubbed out stub = build_stubbed(:user) # Passing a block to any of the methods above will yield the return object create(:user) do |user| user.posts.create(attributes_for(:post)) end

Fuente


Del documento de factory girl, puedes identificar la build estrategias para el user en asociación en post fábrica post como esta:

factory :post do association :user, factory: :user, strategy: :build end

Para que pueda build una post sin guardar user

post = build(:post) post.new_record? # => true post.author.new_record? # => true