2010-06-07 19 views
21

Esto NO es una pregunta sobre cuál es el mejor marco, etc.¿Cómo funcionan los frameworks de burlarse de Java?

Nunca he usado un marco de burla y estoy un poco desconcertado por la idea. ¿Cómo sabe cómo crear el objeto simulado? ¿Se hace en tiempo de ejecución o genera un archivo? ¿Cómo sabes su comportamiento? Y lo más importante: ¿cuál es el flujo de trabajo de usar dicho marco (¿cuál es el paso a paso para crear una prueba)?

¿Alguien puede explicarlo? Puede elegir el marco que desee, por ejemplo, solo diga lo que es.

+2

Puede que no haya deseado las respuestas de "mejor estructura", pero eso es lo que obtendrá ... – skaffman

+0

Vea también http://stackoverflow.com/questions/2277039/how-do-mock-frameworks-work , aunque las respuestas allí son muy técnicas. –

Respuesta

8

Hablaré del framework que uso (jmock), pero otros hacen algo muy similar.

¿Cómo sabe cómo crear el objeto simulado ?

No, le dice al marco que necesita un objeto de simulación y le da un tipo (idealmente una interfaz) del objeto que le gustaría burlarse. Detrás de escena, el marco simulado utiliza una combinación de reflexiones y, a veces, reescrituras de códigos de bytes para crear un objeto simulado.

¿Se hace en tiempo de ejecución o genera un archivo ?

jMock lo crea en tiempo de ejecución.

¿Cómo conoce su comportamiento?

Los objetos falsos son bastante tontos. Usted especifica el comportamiento que espera de ellos.

Y lo más importante - lo que es el flujo de trabajo de utilizar un marco de este tipo (lo que es el paso paso a la creación de una prueba ).

Una cosa muy importante que el framework debe proporcionar es la capacidad de verificar que se haya observado el comportamiento esperado durante la ejecución de la prueba.

jmock lo hace presentando un corredor de prueba específico que verifica que todas las expectativas en todos los objetos simulados declarados hayan finalizado. Si algo no coincide, se lanza la excepción.

Por lo general, el patrón es:

  1. Adquirir fábrica simulada (llamado burla en JMock) de la nada (con específica constructor sin argumentos).
  2. Crea los objetos simulados requeridos.
  3. Configuración expectativa de objetos simulados
  4. llamar al método que se está probando, que pasa burla en lugar de objetos reales
  5. Si el método devuelve algunos valores, cheque con el valor esperado assertXXX métodos regulares.
0

EasyMock (http://easymock.org/) es la biblioteca de burlas que he usado más. (Hay otros: jMock, Mockito, etc.)

La mayoría de estos crean un objeto en tiempo de ejecución, que usted puede controlar. El flujo básico es:

  1. Crear una maqueta
  2. especificar cómo se debe actuar contando el marco simulacro de lo que llama a esperar. (Esto varía en función del marco.)
  3. Utilice el simulacro en su prueba como si fuera el verdadero
  4. Algunos marcos permiten (o requieren) que "verifique" que el simulacro se haya utilizado correctamente.
1

creo que EasyMock's documentation es una manera de conseguir a empezar. Presenta muchos ejemplos que son fáciles de comprender.

5

Para una mejor comprensión de la burla, es posible que desee hacer su propio objeto simulado. Es un proceso bastante simple: crea una clase que implementa la misma interfaz que lo que se burla, y le da el comportamiento que necesita, ya sea grabando llamadas a un método o respondiendo de forma fija cuando se le llama. A partir de ahí, la forma en que se establecen los marcos de burla comienza a tener más sentido.

+0

Me imagino que la biblioteca de simulacro sabe qué interfaz para burlarse, ya que utiliza la reflexión para determinar que la interfaz se parece. –

+0

He creado objetos simulados antes ... Simplemente no usando un marco. –

+0

¿Por qué esto se revocó? Es la única respuesta que aborda la pregunta del OP. –

14

Un marco de burla elimina la redundancia y la repetición de una prueba de burla.

Sabe crear el objeto Mock porque usted se lo dice, por supuesto (a menos que desee decir algo más con esa pregunta).

La forma "estándar" de crear un objeto simulado es usar/abusar de la clase java.lang.reflect.Proxy para crear una implementación en tiempo de ejecución de la interfaz. Esto se hace en tiempo de ejecución. Proxy tiene una limitación en cuanto a que no puede proxy clases concretas. Para lograr la burla de clases concretas se requiere la creación dinámica de códigos de bytes que crea subclases que anulan la implementación real de los métodos públicos, básicamente con lo que se haría con un Proxy (registrar los parámetros del método y devolver un valor predeterminado). Esto tiene una limitación en cuanto a que no puede subclasificar las clases finales. Para eso, tiene soluciones como JDave, que (creo que no confirmé esto) se ensucian con el cargador de clases para eliminar la designación final en la clase antes de cargarla, por lo que la clase no es definitiva en tiempo de ejecución en la medida de lo posible como se trata de la JVM.

El marco de Mocking consiste básicamente en capturar los parámetros y verificarlos contra expectativas predeterminadas, y luego devolver un valor predeterminado preconfigurado o razonable. No se comporta de una manera particular, que es el punto. Se está verificando que el código de llamada llama al método con el parámetro correcto, y tal vez cómo reacciona a un valor de retorno específico o excepciones lanzadas. Cualquier efecto secundario o logro real de la llamada en el objeto real no ocurre.

Aquí hay un ejemplo real de un proyecto, usando JMock con JUnit4. He agregado comentarios para explicar lo que está pasando.

@RunWith(JMock.class) //The JMock Runner automatically checks that the expectations of the mock were actually run at the end of the test so that you don't have to do it with a line of code in every test. 
public class SecuredPresentationMapTest { 

private Mockery context = new JUnit4Mockery(); //A Mockery holds the state about all of the Mocks. The JUnit4Mockery ensures that a failed mock throws the same Error as any other JUnit failure. 

@Test 
public void testBasicMap() { 
    final IPermissionsLookup lookup = context.mock(IPermissionsLookup.class); //Creating a mock for the interface IPermissionsLookup. 
    context.checking(new Expectations(){{ //JMock uses some innovative but weird double brace initialization as its standard idom. 
     oneOf(lookup).canRead(SecuredEntity.ACCOUNTING_CONTRACT); 
      //expect exactly one call to the IPermissionsLookup.canRead method with the the enum of ACCOUNTING_CONTRACT as the value. Failure to call the method at all causes the test to fail. 
      will(returnValue(true)); //when the previous method is called correctly, return true; 
    }}); 

    Map<String, Component> map = new SecuredPresentationMap(lookup, SecuredEntity.ACCOUNTING_CONTRACT); 
    //This creates the real object under test, but passes a mock lookup rather than the real implementation. 
    JLabel value = new JLabel(); 
    map.put("", value); 
    assertThat(((JLabel) map.get("")), is(value)); //This ensures that the Map returns the value placed, which it should based on the fact that the mock returned true to the security check. 
    } 
} 

Si se pasó por alto el simulacro, la prueba habría fallado. Si el mapa no devuelve el valor colocado en él, la prueba falla (que es JUnit estándar).

Lo que se está probando aquí y en otra prueba opuesta es que dependiendo de lo que la interfaz IPermissionsLookup dice acerca de la seguridad del mapa cambia su comportamiento en lo que se devuelve. Este es el buen caso base. La otra prueba, el simulacro devuelve falso y se espera algo más del mapa. Usar el simulacro asegura que el mapa se basa en el método IPermissionsLookup para determinar la postura de seguridad y lo que se devuelve.

+0

debería decir, a causa de JMock, supe de la existencia de la instancia de inicialización (frenos dobles), y de hecho es muy raro si lo ve por primera vez. –

+0

@Alexander, de hecho, las pruebas JMock son las únicas veces que lo uso. Aunque tengo que admitir que tiene un buen lenguaje en este caso particular, yo todavía creo un método abstracto (como AbstractModule de Guice) sería el camino a seguir en el caso general. – Yishai

Cuestiones relacionadas