Problema testeando con rSpec un método

Tengo el siguiente código en mi test:

describe Alineado, “cambiar_por” do
include AlineadoSpecHelper

describe “Con el partido en juego y con cambios disponibles” do
before(:each) do
@partido = mock_model(Partido, {
:cambios_local => 3,
:cambios_visitante => 3,
:en_juego? => true,
:minuto? => 40,
:local => :equipo_local,
:visitante => :equipo_visitante
})
@jugador_sustituido = Alineado.new(atributos_validos(@partido,
:jugador_sustituido, :equipo_local))
@jugador_entrante = Alineado.new(atributos_validos(@partido,
:jugador_entrante, :equipo_local))
@cambios_antes = @partido.cambios_local
@jugador_sustituido.cambiar_por(@jugador_entrante)
end

it "debe de dejar en el banquillo al jugador sustituido" do
  @jugador_sustituido.should be_banquillo
end

it "no debe dejar al jugador entrante en el banquillo" do
  @jugador_entrante.should_not be_banquillo
end

it "debe decrementar en uno el número de cambios disponibles" do
  @partido.cambios_local.should eql(@cambios_antes - 1)
end

end
end

Mi código en el modelo es:

def cambiar_por(jugador_entrante)
salida = self.partido.minuto?
jugador_entrante.entrada = self.partido.minuto?

if club_id == self.partido.local
  self.partido.cambios_local = self.partido.cambios_local - 1
else
  self.partido.cambios_visitante = self.partido.cambios_visitante -

1
end
end
end

Y estos son los errores que recibo:

Spec::Mocks::MockExpectationError in ‘Alineado cambiar_por Con el
partido en juego y con cambios disponibles debe decrementar en uno el
número de cambios disponibles’
Mock ‘Partido_1001’ received unexpected message :cambios_visitante= with
(2)
/home/carlos/NetBeansProjects/ofs/app/models/alineado.rb:47:in
`cambiar_por’
spec/models/alineado_spec.rb:202:
spec/models/alineado_spec.rb:184:

Spec::Mocks::MockExpectationError in ‘Alineado cambiar_por Con el
partido en juego y con cambios disponibles no debe dejar al jugador
entrante en el banquillo’
Mock ‘Partido_1002’ received unexpected message :cambios_visitante= with
(2)
/home/carlos/NetBeansProjects/ofs/app/models/alineado.rb:47:in
`cambiar_por’
spec/models/alineado_spec.rb:202:
spec/models/alineado_spec.rb:184:

Spec::Mocks::MockExpectationError in ‘Alineado cambiar_por Con el
partido en juego y con cambios disponibles debe de dejar en el banquillo
al jugador sustituido’
Mock ‘Partido_1003’ received unexpected message :cambios_visitante= with
(2)
/home/carlos/NetBeansProjects/ofs/app/models/alineado.rb:47:in
`cambiar_por’
spec/models/alineado_spec.rb:202:
spec/models/alineado_spec.rb:184:

¿Qué es lo que estoy haciendo mal?

Buenas,
me da que los errores vienen porque estás llamando a un setter en el
modelo de Alineado(self.partido.cambios_visitante = …) con un modelo
del que has hecho un mock y del que sólo has definido los getters. Mira
a ver si lo tiros van por ahí…
Por cierto, por convencion sólo deberían acabar en interrogación
aquellos métodos que devuelvan un booleano(lo digo por lo de ‘minuto?’)

Salud!

Carlos Belizón escribió:

Borja Martín wrote:

Buenas,
me da que los errores vienen porque estás llamando a un setter en el
modelo de Alineado(self.partido.cambios_visitante = …) con un modelo
del que has hecho un mock y del que sólo has definido los getters. Mira
a ver si lo tiros van por ahí…
Por cierto, por convencion sólo deberían acabar en interrogación
aquellos métodos que devuelvan un booleano(lo digo por lo de ‘minuto?’)

Salud!

Carlos Belizón escribió:

Pensé que la interrogación en Ruby se usaba para no poder modificar
ningún atributo de clase con un método consultor.

Borja Martín wrote:

Buenas,
me da que los errores vienen porque estás llamando a un setter en el
modelo de Alineado(self.partido.cambios_visitante = …) con un modelo
del que has hecho un mock y del que sólo has definido los getters. Mira
a ver si lo tiros van por ahí…
Por cierto, por convencion sólo deberían acabar en interrogación
aquellos métodos que devuelvan un booleano(lo digo por lo de ‘minuto?’)

Salud!

Carlos Belizón escribió:

Este es el modelo Partido de mi aplicación (acabo de añadir la línea
attr_accessible):

class Partido < ActiveRecord::Base
has_many :alineados
attr_accessible :cambios_local, :cambios_visitante

def terminado?
!duracion.nil?
end

def minuto?
hora_actual = DateTime.now
tiempo_transcurrido = fecha - hora_actual
tiempo_transcurrido *= 24 * 60
tiempo_transcurrido = -tiempo_transcurrido.to_i - 1

if tiempo_transcurrido > 115 #Partido terminado
  tiempo_transcurrido = 90
end

if tiempo_transcurrido >= 45 && tiempo_transcurrido < 60 # Descanso
  tiempo_transcurrido 45
end

if tiempo_transcurrido >= 60 && tiempo_transcurrido < 90 # 2ª Tiempo
  tiempo_transcurrido = tiempo_transcurrido - 15
end

if tiempo_transcurrido < 0 #Partido aún no comenzado
  tiempo_transcurrido = nil
end

tiempo_transcurrido

end

def primer_tiempo?
limite_inferior = fecha
limite_superior = fecha.advance(:minutes => 44)
DateTime.now >= limite_inferior && DateTime.now <= limite_superior
end

def segundo_tiempo?
limite_inferior = fecha.advance(:minutes => 60)
limite_superior = fecha.advance(:minutes => 89)
DateTime.now >= limite_inferior && DateTime.now <= limite_superior
end

def en_descanso?
limite_inferior = fecha.advance(:minutes => 45)
limite_superior = fecha.advance(:minutes => 59)
DateTime.now >= limite_inferior && DateTime.now <= limite_superior
end

def en_juego?
primer_tiempo? || segundo_tiempo?
end

def validate
errors.add(:duracion, “no debe ser menor de 90 minutos”) if
!duracion.nil? and duracion < 90
end

end

No tengo idea de qué he de hacer para que el test corra correctamente.

Borja Martín wrote:

El tema es que en tu spec no estás usando la clase Partido para nada ya
que has utilizado mock_model para definir una instancia de pega y en
ningún momento has definido el método ‘cambios_visitante=’ (insisto, en
la clase Partido sí lo tienes, pero realmente no la estás utilizando).
Prueba a crear una instancia de Partido a partir de tu clase en lugar
del mock…

Salud!

Carlos Belizón escribió:

Es que tengo entendido que lo más correcto es usar mocks para hacer test
que implican a otras clases ya que un error en la clase “ajena”, hace
farragoso testear la que estoy testeando. He modificado el stub a
cambios_visitante= y sigo en las mismas…

El tema es que en tu spec no estás usando la clase Partido para nada ya
que has utilizado mock_model para definir una instancia de pega y en
ningún momento has definido el método ‘cambios_visitante=’ (insisto, en
la clase Partido sí lo tienes, pero realmente no la estás utilizando).
Prueba a crear una instancia de Partido a partir de tu clase en lugar
del mock…

Salud!

Carlos Belizón escribió:

Efectivamente por lo que he leido está bien usar los mocks para evitar
dependencias y para poder hacer los specs de tus modelos aunque te
falten otros para desarrollar. Lo decía más que nada para descartar.
¿Cómo pusiste el stub? Por que a mí esto me funciona:

foo.rb

class Foo < ActiveRecord::Base

has_one :bar

def foo
@bar.bar = 1
end

end

bar.rb

class Bar < ActiveRecord::Base
end

#foo_spec.rb

require File.expand_path(File.dirname(FILE) + ‘/…/spec_helper’)

describe Foo do

before(:each) do
@bar = mock_model(Bar, :bar= => 1)
@foo = Foo.new(:bar => @bar)
end

it “should foo” do
@foo.foo.should be_equal(1)
end
end

Saludos

Carlos Belizón escribió:

Borja Martín wrote:

Si no uso un mock el test corre perfectamente, pero claro, la idea es
testear el modelo Alineado sin usar una instancia de Partido real. En tu
ejemplo, para hacer algo parecido a lo que estoy haciendo sería hacer
esto:

#foo.rb

class Foo < ActiveRecord::Base
has_one :bar

def foo
@bar.bar = @bar.bar - 1
end
end

#bar.rb
class Bar < ActiveRecord::Base
end

#foo_spec.rb
require File.expand_path(File.dirname(FILE) + ‘/…/spec_helper’)

describe Foo do
before(:each) do
@bar = mock_model(Bar, :bar= => 1)
@foo = Foo.new(:bar => @bar)
@valor_antes = @foo.bar
end

it “should foo” do
@foo.foo.should be_equal(@valor_antes - 1)
end
end

Que lanza el siguiente error:

Spec::Mocks::MockExpectationError in ‘Foo should foo’
Mock ‘Bar_1001’ received unexpected message :bar with (no args)
/home/carlos/NetBeansProjects/prueba/app/models/foo.rb:5:in `foo’
/home/carlos/NetBeansProjects/prueba/spec/models/foo_spec.rb:11:

Estamos en la misma situación que antes. Ahora estás llamando al método
#bar de tu instancia @bar que tampoco lo tienes definido ya que estás
usando un mock.
Prueba a añadirle el stub :bar => a ver si te funciona.
Por cierto, para decrementar queda mejor @bar.bar -= 1 (o incrementar
‘+=’) :slight_smile:

Salud!

Carlos Belizón escribió:

Borja Martín wrote:

Estamos en la misma situación que antes. Ahora estás llamando al método
#bar de tu instancia @bar que tampoco lo tienes definido ya que estás
usando un mock.
Prueba a añadirle el stub :bar => a ver si te funciona.
Por cierto, para decrementar queda mejor @bar.bar -= 1 (o incrementar
‘+=’) :slight_smile:

Salud!

Carlos Belizón escribió:

No entiendo que quieres decir con :bar => , ¿Es posible que lo
que esté intentando hacer sea imposible o una mala forma de testear?

Borja Martín wrote:

Me refería a esto:
@bar = mock_model(Bar, :bar => 2, :bar= => 1)

Saludos

Carlos Belizón escribió:

Ah, bien bien, ahora me lanza el siguiente error:

Spec::Mocks::MockExpectationError in ‘Foo should foo’
Mock ‘Bar_1001’ received unexpected message :- with (1)
/home/carlos/NetBeansProjects/prueba/spec/models/foo_spec.rb:15:

La verdad es que estoy un poco perdido.

Me refería a esto:
@bar = mock_model(Bar, :bar => 2, :bar= => 1)

Saludos

Carlos Belizón escribió: