Estoy emocionado porque acabo de terminar mi primer test unitario usando mock objects. He comprobado un validador JSF que ha hecho un compañero sin necesidad de ejecutarlo dentro del contenedor web y sin tener que codificar un costoso contexto (que podría, además, incorporar defectos ajenos al sujeto de la prueba -el validador-).

He probado jMock e EasyMock y me he quedado con EasyMock. Os enseño los dos ejemplos:

Con jMock:

import org.jmock.Expectations;import org.jmock.Mockery;import org.jmock.integration.junit4.JMock;import org.jmock.integration.junit4.JUnit4Mockery;import org.junit.Test;import org.junit.runner.RunWith;

@RunWith(JMock.class)public class PublisherTest {

	Mockery context = new JUnit4Mockery();

	/**	 * A Publisher sends a message to a single registered Subscriber.	 * 	 */	 public void oneSubscriberReceivesAMessage() {

		/*		 * We first set up the context in which our test will execute. We create		 * a Publisher to test. We create a mock Subscriber that should receive		 * the message. We then register the Subscriber with the Publisher.		 * Finally we create a message object to publish.		 */

		// set up		final Subscriber subscriber = context.mock(Subscriber.class);

		Publisher publisher = new Publisher();		publisher.add(subscriber);

		final String message = "message";

		/*		 * Next we define expectations on the mock Subscriber that specify the		 * methods that we expect to be called upon it during the test run. We		 * expect the receive method to be called once with a single argument,		 * the message that will be sent.		 */

		// expectations		context.checking(new Expectations() {			{				one(subscriber).receive(message);			}		});

		/*		 * We then execute the code that we want to test.		 */

		// execute		publisher.publish(message);

		/*		 * After the code under test has finished our test must verify that the		 * mock Subscriber was called as expected. If the expected calls were		 * not made, the test will fail. The MockObjectTestCase does this		 * automatically. You don't have to explicitly verify the mock objects		 * in your tests. The JMock test runner does this automatically. You		 * don't have to explicitly verify the mock objects in your tests.		 */		// mockery.assertIsSatisfied();

	}}

Con EasyMock:

import org.easymock.EasyMock;import org.junit.Test;

public class PublisherTest {

	private Publisher publisher;	private Subscriber subscriber;

	/**	 * A Publisher sends a message to a single registered Subscriber.	 * 	 */	 public void oneSubscriberReceivesAMessage() {

		// create the collaborators as mocks		subscriber = EasyMock.createMock(Subscriber.class); 

		// setup		publisher = new Publisher();		publisher.add(subscriber);		final String message = "message";

		// expectations		subscriber.receive(message);		EasyMock.expectLastCall().times(2);

		// end setup		EasyMock.replay(subscriber);

		// execution		publisher.publish(message);		publisher.publish(message);

		// assertion		EasyMock.verify(subscriber);	}

}

Como se puede comprobar, el código del test con EasyMock es más intuitivo. Sólo una salvedad: si queréis hacer “mocks” de clases abstractas necesitaréis también “EasyMock Class Extension” y CGLIB (yo me he descargado cglib-nodep-2.1_3.jar para evitar problemas de dependencias).

Las ventajas de hacer tests con “mocks” son:

  • evitamos costosas “fixtures” (objetos creados ad-hoc como contexto de la prueba) que, además, pueden introducir/ocultar defectos
  • podemos probar el comportamiento de nuestro sujeto (no sólo el estado final)

Esto último es especialmente necesario en el caso de componentes a los que no podamos decirle assertEquals de nada y que debamos comprobar que interactúa con sus colaboradores como se haya definido.

0saves
Si te ha gustado esta entrada, por favor deja un comentario o subscríbete al canal RSS.