¿Cuál es el mejor marco de trabajo para crear objetos simulados en Java? ¿Por qué? ¿Cuáles son los pros y los contras de cada framework?
He tenido buen éxito usando Mockito.
Cuando traté de aprender sobre JMock y EasyMock, encontré que la curva de aprendizaje era un poco empinada (aunque tal vez eso'es sólo yo).
Me gusta Mockito por su sintaxis simple y limpia que pude entender bastante rápido. La sintaxis mínima está diseñada para soportar los casos comunes muy bien, aunque las pocas veces que necesité hacer algo más complicado encontré que lo que quería era soportado y fácil de entender.
Aquí's un ejemplo (abreviado) de la página web de Mockito:
import static org.mockito.Mockito.*;
List mockedList = mock(List.class);
mockedList.clear();
verify(mockedList).clear();
No hay nada más sencillo que eso.
La única desventaja importante que se me ocurre es que no se burla de los métodos estáticos.
Soy el creador de PowerMock, así que obviamente debo recomendarlo. :-)
[PowerMock][1] extiende tanto EasyMock como Mockito con la capacidad de [burlar los métodos estáticos][2], métodos finales e incluso privados. El soporte de EasyMock está completo, pero el plugin Mockito necesita algo más de trabajo. Estamos planeando añadir soporte para JMock también.
PowerMock no está pensado para reemplazar otros frameworks, sino que puede ser usado en las situaciones complicadas cuando otros frameworks lo hacen'no permiten la burla. PowerMock también contiene otras características útiles como [suprimir los inicializadores estáticos][3] y los constructores.
[1]: http://powermock.org [2]: http://code.google.com/p/powermock/wiki/MockStatic [3]: http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior
El sitio del proyecto de http://jmockit.org"a href="http://jmockit.org"JMockit contiene mucha información comparativa para los actuales conjuntos de herramientas de burla.
En particular, echa un vistazo a la <a href="http://jmockit.org/MockingToolkitComparisonMatrix.html";matriz de comparación de características**, que cubre EasyMock, jMock, Mockito, Unitils Mock, PowerMock, y por supuesto JMockit. Intento mantenerlo preciso y actualizado, tanto como sea posible.
He tenido éxito con JMockit.
Es bastante nuevo, así que es un poco crudo y poco documentado. Utiliza ASM para redefinir dinámicamente el código de bytes de la clase, de modo que puede burlar todos los métodos incluyendo estáticos, privados, constructores e inicializadores estáticos. Por ejemplo:
import mockit.Mockit;
...
Mockit.redefineMethods(MyClassWithStaticInit.class,
MyReplacementClass.class);
...
class MyReplacementClass {
public void $init() {...} // replace default constructor
public static void $clinit{...} // replace static initializer
public static void myStatic{...} // replace static method
// etc...
}
Tiene una interfaz de Expectativas que permite escenarios de grabación/reproducción también:
import mockit.Expectations;
import org.testng.annotations.Test;
public class ExpecationsTest {
private MyClass obj;
@Test
public void testFoo() {
new Expectations(true) {
MyClass c;
{
obj = c;
invokeReturning(c.getFoo("foo", false), "bas");
}
};
assert "bas".equals(obj.getFoo("foo", false));
Expectations.assertSatisfied();
}
public static class MyClass {
public String getFoo(String str, boolean bool) {
if (bool) {
return "foo";
} else {
return "bar";
}
}
}
}
La desventaja es que requiere Java 5/6.
También podrías echar un vistazo a las pruebas usando Groovy. En Groovy puedes burlarte fácilmente de las interfaces de Java usando el 'as' operador:
def request = [isUserInRole: { roleName -> roleName == "testRole"}] as HttpServletRequest
Aparte de esta funcionalidad básica Groovy ofrece mucho más en el frente burlón, incluyendo las poderosas clases MockFor
y StubFor
.
Empecé a usar burlas con [EasyMock][1]. Bastante fácil de entender, pero el paso de repetición fue un poco molesto. [Mockito][2] elimina esto, también tiene una sintaxis más limpia ya que parece que la legibilidad era uno de sus principales objetivos. No puedo enfatizar lo importante que es esto, ya que la mayoría de los desarrolladores pasarán su tiempo leyendo y manteniendo el código existente, no creándolo.
Otra cosa buena es que las interfaces y las clases de implementación se manejan de la misma manera, a diferencia de EasyMock, donde aún hay que recordar (y comprobar) que se debe usar una extensión de clase EasyMock.
He echado un vistazo rápido a [JMockit][3] recientemente, y aunque la lista de características es bastante completa, creo que el precio de esto es la legibilidad del código resultante, y tener que escribir más.
Para mí, Mockito tiene su punto fuerte, siendo fácil de escribir y leer, y lidiando con la mayoría de las situaciones que la mayoría del código requerirá. Usar [Mockito][2] con [PowerMock][4] sería mi elección.
Una cosa a tener en cuenta es que la herramienta que elegirías si estuvieras desarrollando por ti mismo, o en un pequeño equipo de trabajo, podría no ser la mejor para una gran compañía con desarrolladores de diferentes niveles de habilidad. La legibilidad, la facilidad de uso y la simplicidad necesitarían más consideración en este último caso. No tiene sentido obtener el marco de burla definitivo si mucha gente termina no usándolo o no manteniendo las pruebas.
[1]: http://easymock.org/ [2]: http://code.google.com/p/mockito/ "Mockito" [3]: http://jmockit.org/ "JMockit" [4]: http://code.google.com/p/powermock/
En el trabajo usamos mucho EasyMock y EasyMock Class Extension y estamos bastante contentos con ellos. Básicamente te da todo lo que necesitas. Echa un vistazo a la documentación, hay un ejemplo muy bonito que muestra todas las características de EasyMock.
Usé JMock antes. He probado Mockito en mi último proyecto y me ha gustado. Más conciso, más limpio. PowerMock cubre todas las necesidades que están ausentes en Mockito, como burlarse de un código estático, burlarse de la creación de una instancia, burlarse de las clases y métodos finales. Así que tengo todo lo que necesito para realizar mi trabajo.
Me gusta JMock porque es capaz de crear expectativas. Esto es totalmente diferente a comprobar si un método fue llamado encontrado en algunas bibliotecas de prueba. Usando JMock puedes escribir expectativas muy sofisticadas. Mira el jmock [cheat-sheat][1].
La mejor solución para burlarse es que la máquina haga todo el trabajo con pruebas automatizadas basadas en especificaciones. Para Java, ver [ScalaCheck][1] y el marco de trabajo [Reductio][2] incluido en la biblioteca [Java funcional][3]. Con los marcos de trabajo de pruebas automatizadas basadas en especificaciones, se suministra una especificación del método bajo prueba (una propiedad sobre él que debería ser verdadera) y el marco de trabajo genera pruebas así como objetos de prueba, automáticamente.
Por ejemplo, la siguiente propiedad prueba el método Math.sqrt para ver si la raíz cuadrada de cualquier número positivo n al cuadrado es igual a n.
val propSqrt = forAll { (n: Int) => (n >= 0) ==> scala.Math.sqrt(n*n) == n }
Cuando llamas a propSqrt.check()
, ScalaCheck genera cientos de enteros y comprueba su propiedad para cada uno, también automáticamente asegurándose de que los casos de borde están bien cubiertos.
Aunque ScalaCheck está escrito en Scala, y requiere el Compilador de Scala, es fácil probar el código Java con él. El marco de trabajo Reductio en Java funcional es una implementación pura de Java de los mismos conceptos.
[1]: http://www.scalacheck.org/ [2]: http://functionaljava.googlecode.com/svn/artifacts/2.17/javadoc/fj/test/package-summary.html [3]: http://functionaljava.org
Mockito también proporciona la opción de métodos de stubbing, emparejando argumentos (como anyInt() y anyString()), verificando el número de invocaciones (times(3), atLeastOnce(), never()), y más.
También he encontrado que Mockito es simple y limpio.
Una cosa que no me gusta de Mockito es que puede't t tachar los métodos estáticos.
Para algo un poco diferente, podrías usar [JRuby][1] y [Mocha][2] que se combinan en [JtestR][3] para escribir pruebas para tu código Java en expresivo y sucinto Ruby. Hay algunos ejemplos útiles de burla con JtestR [aquí][4]. Una ventaja de este enfoque es que burlarse de clases concretas es muy sencillo.
[1]: http://jruby.codehaus.org/ [2]: http://mocha.rubyforge.org/ [3]: http://docs.codehaus.org/display/JTESTR/Home [4]: http://docs.codehaus.org/display/JTESTR/Mocks