¿Cómo testear el callback after_cre ate?

Hola lista… No se qué me pasa hoy pero no consigo testear una cosa
que creo que es una tontería.

Supongamos el típico escenario de un modelo que has_many otro. Por
ejemplo, para una tienda de discos, tenemos el modelo Disco y el
modelo Caratula:

class Disco < ActiveRecord::Base
has_many :caratulas
end

class Caratula < ActiveRecord::Base
belongs_to :disco
end

Bien, quiero testear que cuando se crea un nuevo Disco, se le crea
automáticamente una primera carátula. Para ello uso este test en el
test unitario de Disco:

def test_crear_primera_caratula
disco = Disco.create(:titulo => ‘Remain in Light’)

assert_equal 1, disco.caratulas.size
end

Siguiendo TDD, el test falla, y entonces voy al modelo Disco y
programo esto con after_create:

class Disco < ActiveRecord::Base
has_many :caratulas

after_create :crear_primera_caratula

protected
def create_primera_caratula
self.caratulas.create()
end

end

Pero nada… el test me dice que disco.caratulas.size es 0, y esperaba
1.

Lo curioso es que desde script/console o directamente desde la web, sí
que funciona, hace el after_create y se crea la carátula.

Me da la impresión de que en los tests unitarios no se lanzan los
callbacks… ¿Cómo hacerlo entonces?

Hola Jaime,

parece que hoy es el día de los tests…

Quizá si poniendo un disco.reload entre la creación y el assert tal que
así:
def test_crear_primera_caratula
disco = Disco.create(:titulo => ‘Remain in Light’)
disco.reload
assert_equal 1, disco.caratulas.size
end

Pero vamos, no lo he probado :S

2008/1/29 Jaime I. [email protected]:

Hola Fernando, ya probé con el reload pero entonces me da este error:

ActiveRecord::RecordNotFound: Couldn’t find Disco without an ID

Y eso ya me toca más la moral. :smiley:

Jaimes

El 30/01/08, Fernando B. [email protected]
escribió:> Hola Jaime,

Hola Jaime,

¿Puede ser que el disco que creas en tu test no sea válido? En ese caso
no se crearían carátulas porque al no guardarse el disco no se ejecuta
el callback (y tampoco te dejaría hacer el reload porque aún no tiene ID
asignado en la base de datos).

En este tipo de tests yo meto siempre un assert_valid mientras los
desarrollo, más que nada para asegurarme de que el caso de prueba es el
que necesito. El test
quedaría así:
def test_crear_primera_caratula
disco = Disco.create(:titulo => ‘Remain in Light’)
assert_valid disco

assert_equal 1, disco.caratulas.size
end

Si el disco no es válido el assert_valid te mostrará los errores de
validación. Y si el disco es válido… entonces creo que hay algo
colateral en tu código que se nos escapa, porque en lo que enviaste a la
lista no veo problema ninguno.


Raul M. - Freelance Web D.
http://raul.murciano.net

O también puedes utilizar los helpers assert_difference que van en el
plugin acts_as_authenticated pero que creo que ya han incluído en
Rails 2:

def test_crear_primera_caratula
assert_differece Caratulas, :count do
assert_difference Disco, :count do
disco = Disco.create(:titulo => ‘Remain in Light’)
assert disco.valid?
end
end
end

2008/1/30 Raul M. [email protected]:

Gracias a todos por vuestra ayuda, al final era culpa mía, que no estaba
haciendo bien el create del primer modelo y algo colateral se disparaba
por
ahí, se ve.

En resumen: que los after_create sí que se ejecutan en modo testing.

Me ha venido bien también para probar a testearlo de la manera que
propone
Fernando. La sintaxis correcta es o, al menos, la que hace juego con mis
pantalones, es la siguiente. Es curioso que hay que pasarle al
assert_difference el parámetro como string.

def test_crear_primera_caratula
assert_difference(‘Caratula.count’) do
assert_difference(‘Disco.count’) do
disco = Disco.create(:titulo => ‘Remain in Light’)
assert disco.valid?
end
end
end

def test_crear_primera_caratula
assert_difference(‘Caratula.count’) do

assert_difference(‘Disco.count’) do

 disco = Disco.create(:titulo => 'Remain in Light')
 assert disco.valid?
end

end
end

FYI, en stage utilizamos la tecnica de projectionist para hacer los
assert_difference mas inteligibles:

def assert_difference(object, method = nil, difference = 1)
initial_value = object.send(method)
yield
assert_equal initial_value + difference, object.send(method),
“#{object}##{method}”
end

def assert_no_difference(object, method, &block)
assert_difference object, method, 0, &block
end

Esto permite cambiar el test a algo como:

assert_difference Ticket, :count, 1 do
  ticket = create_ticket
  assert !ticket.new_record?, 

“#{ticket.errors.full_messages.to_sentence}”
end


Kind Regards,
Aitor Garcia
Cofounder - Linking Paths
http://www.linkingpaths.com

Mira si una cosa parecida te funciona …


post.rb

class Post < ActiveRecord::Base
has_many :comments
after_create :add_comment
def add_comment
self.comments.create(:body => “Sample comment”)
end
end

post_test.rb

require File.dirname(FILE) + ‘/…/test_helper’
class PostTest < ActiveSupport::TestCase

Replace this with your real tests.

def test_should_add_comment_after_creating_a_post
posts_count, comments_count = Post.count, Comment.count
@post = Post.create(:title => “This is chelm”)
assert_equal Post.count, posts_count + 1
assert_equal @post.comments.size, comments_count + 1
end
end

tiramos el test …

[sueisfine]$ ruby test/unit/post_test.rb
Loaded suite test/unit/post_test
Started
.
Finished in 0.130431 seconds.

1 tests, 2 assertions, 0 failures, 0 errors


Un saludo,

Francesc

On Jan 30, 2008, at 8:11 AM, Fernando B. wrote:

end

el callback (y tampoco te dejaría hacer el reload porque aún no

Raul M. - Freelance Web D.


Fernando B.
blog > http://www.inwebwetrust.net


Ror-es mailing list
[email protected]
simplelogica.net


name. Francesc E. i Martí
voice. +34 678.681.603