Tuesday, 30 June 2009

Mock Objects

Continuando en la misma línea del Test Driven Development, existe una evolución o mejora de los xUnit basada en los Mock Objects. Los Mock Objects utilizan una técnica para que el diseño del software se haga sobre el TDD. Al igual que los xUnit, podemos encontrar ésta técnica en varios lenguajes de programación: java (jMock y EasyMock), Delphi (pascalMock), .NET (NMock), etc. Aquí os mostraré un par de ejemplos sobre la implementación en Java y Delphi.
  • Utilizando jMock:
Para este ejemplo, nos descargaremos el jMock de la web en éste caso la versión 2.5.1 (jmock-2.5.1), y la última versión del jUnit (la 4.6) -> jUnit-4.6.jar. Una vez tenemos todos los .jar descargados, tenemos que añadirlos en el class path de nuestro proyecto. Por lo tanto tenemos que vincularlo de la siguiente manera:

Voy a aprovechar el ejemplo que posteé ayer sobre la clase TArithmetic, y la he implementado en java para simular el mismo comportamiento. Además es muy fácil de seguir sin complicar mucho el código.

De acuerdo con el TDD, primero tenemos que crear el test case:




/**
* @Author : Jordi Coll
* Test With Mock Objects
*/
import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class TestJMockIniCase {
@Test
public void testSayGreeting(){
Arithmetic a = new Arithmetic();
assertEquals(0, a.plus());
}
}





En este caso, como no hemos creado la clase Arithmetic da un error. Para hacer que compile, necesito crear la clase. Luego tenemos que crear una clase llamada ComponentArithmetic que es la que comunicará con la clase Arithmetic para entregarle las variables x y y para sus cálculos. Luego explicaremos el porqué de esto.

Aquí está la clase Arithmetic:




/**
* @Author : Jordi Coll
* Test With Mock Objects
*/
public class Arithmetic {
private ComponentArithmetic component;

public void SetComponent(ComponentArithmetic component) {
this.component = component;
}

public int plus () {
return component.getX() + component.getY();
}

public int minus() {
return component.getX() - component.getY();
}

public int multiply () {
return component.getX() * component.getY();
}

public int divide () {
return component.getX() / component.getY();
}

public float floating () {
return (float)component.getX() / (float)component.getY();
}

public float sin () {
return (float)Math.sin(Math.toRadians(component.getX()));
}

public float cos () {
return (float) Math.cos(Math.toRadians(component.getX()));
}
}




Para seguir con la compilación, tenemos que crear la clase ComponentArithmetic. Como queremos utilizar mock objects, debemos crear ésta como una interfaz:




/**
* @Author : Jordi Coll
* Test With Mock Objects
*/
public interface ComponentArithmetic {
public int getX();
public int getY();
}




Uno de los pre-requisitos para el uso de los mock objects, es que la clase que parametrizaremos la tenemos que declarar como una interfaz. Además, tenemos que utilizar métodos setter para inyectar la instancia de ComponentArithmetic a Arithmetic. (No podemos utilizar la notación "new" en una interfaz).

Ahora, solo tenemos que modificar la clase de test para que cumpla con nuestras expectativas:




/**
* @Author : Jordi Coll
* Test With Mock Objects
*/

import org.jmock.Expectations;
import org.jmock.Mockery;

import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMock.class)
public class TestUsingjMock {
//Creamos el contexto para el mock Object
Mockery context = new JUnit4Mockery();

@Test
public void testArithmetic() {
//Mock sobre la clase ComponentArithmetic utilizando la tecnologia de refexión
//La tenemos que definir como variable final
//ya que va a ser utilizada como clase interna
final ComponentArithmetic ca = context.mock(ComponentArithmetic.class);
Arithmetic a = new Arithmetic();
a.SetComponent(ca);

//Ponemos lo que vamos a esperar del mock Object
context.checking(new Expectations() {
{
one(ca).getX();
will(returnValue(2));
one(ca).getY();
will(returnValue(2));
}
});

int plus = a.plus();
//comparamos el resultado con el valor esperado
assertEquals(3, plus);
}
}




(Todo el tema de los expectators lo podemos encontrar en la web del jUnit : http://www.jmock.org/cookbook.html)

Ahora, si ejecutamos el test con el JUnit, obtendremos:

Prueba correcta:

Prueba con error:
  • Utilizando Pascal Mock:
Podemos encontrar la última versión de Pascal Mock en SourceForge. La última versión estable es la 1.1, y podemos descargarla directamente desde aquí. Su utilización es muy parecida al DUnit y hay que generar las interfases necesarias para que los mock object actúen. Podremos encontrar muchos ejemplos dentro del código. El ejemplo que hay dentro del proyecto, lo podemos ejecutar y visualizar:

Es un proyecto que no está muy vivo (desde el 2007 sin ninguna actualización) y es bastante más complicado de utilizar que con java.

0 comments:

Post a Comment