mock - ¿Cómo burlarse de un método con argumentos funcionales en Scala?
java mock (3)
Este problema parece ser específico para invocaciones de nombre porque en las funciones regulares de orden superior puede hacer coincidir con el objeto FunctionX explícito:
verificar (colaborador) .somethingElse (cualquiera (Function2 [String, Thing]))
en el caso de by-name, el ajuste del argumento en una Function0 se realiza de manera implícita, y la respuesta de Alexey muestra cómo invocar el simulacro con un parámetro explícito.
Puedes escribir algo similar a tu propio verificador que aplique los argumentos capturados por mockito.
Mockito registra internamente la invocación y sus argumentos con, por ejemplo, http://code.google.com/p/mockito/source/browse/trunk/src/org/mockito/internal/matchers/CapturingMatcher.java
Estoy intentando burlar una llamada de método que toma un argumento de llamada por nombre:
import org.scalatest.WordSpec
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
trait Collaborator {
def doSomething(t: => Thing)
}
trait Thing
@RunWith(classOf[JUnitRunner])
class Test extends WordSpec with MockitoSugar {
"The subject under test" should {
"call the collaborator" in {
// setup
val m = mock[Collaborator]
val t = mock[Thing]
// test code: this would actually be invoked by the SUT
m.doSomething(t)
// verify the call
verify(m).doSomething(t)
}
}
}
Estoy interesado principalmente en Mockito ya que eso es lo que estoy usando, pero me gustaría ver si alguno de los principales marcos simulados es capaz de realizar este tipo de pruebas. La prueba falla en el tiempo de ejecución en la línea de verify
, con un error como
Argument(s) are different! Wanted: collaborator.doSomething( ($anonfun$apply$3) <function> ); -> at Test$$anonfun$1$$anonfun$apply$1.apply(Test.scala:27) Actual invocation has different arguments: collaborator.doSomething( ($anonfun$apply$2) <function> ); -> at Test$$anonfun$1$$anonfun$apply$1.apply(Test.scala:24)
Si estoy entendiendo la situación correctamente, el compilador está envolviendo implícitamente t
en una función nula que devuelve t
. El marco simulado luego compara esa función con la producida en el código de prueba, que es equivalente pero no equals()
.
Mi caso es una versión relativamente simple del problema, pero creo que este sería un problema con cualquier función de orden superior.
Esto parece feo, pero espero que pueda ayudarlo a encontrar una buena solución:
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
trait Collaborator {
def doSomething(t: => Thing)
}
trait Thing
new MockitoSugar {
// setup
val m = mock[Collaborator]
val t = mock[Thing]
m.doSomething(t)
classOf[Collaborator].getMethod("doSomething", classOf[Function0[_]]).invoke(
verify(m),
new Function0[Thing] {
def apply() = null
override def equals(o: Any): Boolean = t == o.asInstanceOf[Function0[Thing]].apply()
})
}
Puedes probar specs2 . En las especificaciones 2, "secuestramos" la clase de Invocation
Mockito para tener en cuenta los parámetros de nombre:
trait ByName { def call(i: =>Int) = i }
val byname = mock[ByName]
byname.call(10)
there was one(byname).call(10)