Introducción a los dobles para pruebas

Como ya he comentado en artículos anteriores, los tests de unidad deben ser independientes y autocontenidos, deberían utilizar la mínima cantidad de infraestructura necesaria para hacer sus pruebas, y deberían estar escritos de forma que sólo fallen o tengan éxito si la unidad que estamos probando falla o funciona correctamente.

Con esto en mente, vamos a escribir unos cuantos tests de unidad para esta clase:

public class WebPageTranslator {
	public String translate(String url, String fromLanguage, String toLanguage) {
		Downloader downloader = new HttpDownloader();
		String page = downloader.download(url);
		if (page == null || fromLanguage.equals(toLanguage)) {
			return page;
		}
		Translator translator = new GoogleTranslator();
		return translator.translate(page, fromLanguage, toLanguage);
	}
}

Como podéis apreciar, vamos a tener un problema bastante gordo a la hora de escribir tests, independientes, autocontenidos y con poca infraestructura. En particular, esta clase depende de HttpDownloader y de GoogleTranslator, que (se supone) siempre descargan contenido de la web y utilizan Google Translate. Esto significa que nuestros tests también dependerán de estas dos clases, por lo que no serán autocontenidos, y podrán fallar si por algún motivo no se puede descargar algo de la web o Google Translate no responde.

Para solucionar este problema debemos rediseñar la clase para que se le puedan inyectar sus dependencias, y utilizar en lugar de HttpDownloader y GoogleTranslator unas clases especiales para pruebas que no necesiten acceder a Internet ni a los servicios de Google:

public class WebPageTranslator {
	private final Downloader downloader;
	private final Translator translator;

	@Inject
	public WebPageTranslator(Downloader downloader, Translator translator) {
		this.downloader = downloader;
		this.translator = translator;
	}

	public String translate(String url, String fromLanguage, String toLanguage) {
		String page = downloader.download(url);
		if (page == null || fromLanguage.equals(toLanguage)) {
			return page;
		}
		return translator.translate(page, fromLanguage, toLanguage);
	}
}

Vamos a escribir ahora unos cuantos tests de unidad, y veremos más adelante cómo serían estas dos clases especiales para tests:

@Test
public void testTranslate() {
	Downloader downloader = new StubDownloader("Valeu!");
	Translator translator = new MockTranslator("Valeu!", "Thank you!",
			"pt", "en");
	WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
			translator);
	assertEquals("Thank you!", pageTranslator.translate(
			"http://example.com/valeu.html", "pt", "en"));
}

@Test
public void doesNotTranslateWhenLanguagesAreEqual() throws Exception {
	Downloader downloader = new StubDownloader("Valeu!");
	Translator translator = new DummyTranslator();
	WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
			translator);
	assertEquals("Valeu!", pageTranslator.translate(
			"http://example.com/valeu.html", "pt", "pt"));
}

@Test
public void returnsNullWhenDownloadFails() throws Exception {
	Downloader downloader = new StubDownloader(null);
	Translator translator = new DummyTranslator();
	WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
			translator);
	assertNull(pageTranslator.translate("http://example.com/valeu.html",
			"pt", "en"));
}

@Test
public void returnsNullWhenTranslatorFails() throws Exception {
	Downloader downloader = new StubDownloader("Valeu!");
	Translator translator = new MockTranslator("Valeu!", null, "pt", "en");
	WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
			translator);
	assertNull(pageTranslator.translate("http://example.com/valeu.html",
			"pt", "en"));
}

Aquí tenemos cuatro tests, que comprueban qué ocurre en el caso normal, cuando el idioma de origen y de destino son el mismo, cuando falla la descarga del texto y cuando falla la llamada al traductor. Para cada uno de estos tests estamos utilizando instancias de StubDownloader, MockTranslator y DummyTranslator, que son clases especiales que hemos creado para los tests, que cumplen las interfaces Downloader y Translator pero que hemos implementado de forma muy simple y están bajo nuestro completo control.

Veamos qué hacen estas tres clases:

La clase StubDownloader devuelve siempre el mismo valor cuando se llama a su método translate(); este valor es el que le hemos pasado en el constructor. En todos los tests este valor es el texto de la página que queremos traducir; en el segundo test, sin embargo, el valor es null para simular un fallo en la descarga.

La clase MockTranslator comprueba que, cuando llamamos al método translate(), le pasamos parámetros con ciertos valores esperados, y si es así, devuelve un resultado predeterminado. Como en el caso anterior, estos valores esperados y resultado predeterminado se le pasan en el constructor.

La clase DummyTranslator no hace nada; simplemente existe para poder inyectar un objeto de tipo Translator en los tests en los que no se realiza ninguna llamada a translate().

Aquí está el código completo de los tests de unidad y de esas tres clases, por si tenéis curiosidad:

public class WebPageTranslatorTest {
	@Test
	public void testTranslate() {
		Downloader downloader = new StubDownloader("Valeu!");
		Translator translator = new MockTranslator("Valeu!", "Thank you!",
				"pt", "en");
		WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
				translator);
		assertEquals("Thank you!", pageTranslator.translate(
				"http://example.com/valeu.html", "pt", "en"));
	}

	@Test
	public void doesNotTranslateWhenLanguagesAreEqual() throws Exception {
		Downloader downloader = new StubDownloader("Valeu!");
		Translator translator = new DummyTranslator();
		WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
				translator);
		assertEquals("Valeu!", pageTranslator.translate(
				"http://example.com/valeu.html", "pt", "pt"));
	}

	@Test
	public void returnsNullWhenDownloadFails() throws Exception {
		Downloader downloader = new StubDownloader(null);
		Translator translator = new DummyTranslator();
		WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
				translator);
		assertNull(pageTranslator.translate("http://example.com/valeu.html",
				"pt", "en"));
	}

	@Test
	public void returnsNullWhenTranslatorFails() throws Exception {
		Downloader downloader = new StubDownloader("Valeu!");
		Translator translator = new MockTranslator("Valeu!", null, "pt", "en");
		WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
				translator);
		assertNull(pageTranslator.translate("http://example.com/valeu.html",
				"pt", "en"));
	}

	private class StubDownloader implements Downloader {
		private final String response;

		public StubDownloader(String response) {
			this.response = response;
		}

		@Override
		public String download(String url) {
			return response;
		}
	}

	private class DummyTranslator implements Translator {
		@Override
		public String translate(String text, String fromLanguage,
				String toLanguage) {
			throw new IllegalStateException();
		}
	}

	private class MockTranslator implements Translator {
		private final String text;
		private final String translation;
		private final String from;
		private final String to;

		public MockTranslator(String text, String translation, String from,
				String to) {
			super();
			this.text = text;
			this.translation = translation;
			this.from = from;
			this.to = to;
		}

		@Override
		public String translate(String text, String from, String to) {
			if (text.equals(this.text) && from.equals(this.from)
					&& to.equals(this.to)) {
				return translation;
			} else {
				throw new IllegalStateException(
						"translate() called with wrong arguments");
			}
		}
	}
}

Las tres clases que describí arriba son tres ejemplos de lo que en inglés llaman “test doubles” (podríamos llamarlas “dobles para pruebas” en español). Los dobles para pruebas son clases que se utilizan en los tests para sustituir a clases que requieren mucha infraestructura, se ejecutan lentamente, son difíciles de utilizar, etc. La gente que trabaja en el asunto suele distinguir cuatro tipos: “dummy”, “stub”, “mock” y “fake”. Los tres primeros tipos los hemos visto en los ejemplos anteriores; el cuarto, “fake”, es una implementación completa del interfaz utilizando tablas hash y otros sistemas para mantener todo en memoria en lugar de usar la red, el disco, la base de datos, etc.

No existen unos criterios bien formados sobre cuándo utilizar uno u otro tipo de doble para pruebas; en general, se utiliza lo que sea más fácil de usar y proporcione unos resultados más fiables. Por ejemplo, los objetos “fake” suelen tener un comportamiento muy similar al del objeto al que sustituyen, pero pueden necesitar mucho código para ponerlos en el estado adecuado para cada test. Los objetos “mock” o “stub” son más fáciles de preparar, pero si la persona que los usa no entiende bien cómo funciona el objeto al que sustituyen, pueden causar falsos positivos o negativos en los tests; además, los tests hechos a base de mocks suelen necesitar muchos cambios si cambia la implementación del objeto al que prueban, lo que no ocurre con tanta frecuencia en los tests hechos a base de fakes.

Otro inconveniente de los mocks es que hace falta escribir mucho código para definirlos; la clase MockTranslator, por ejemplo, tiene 26 líneas y no es particularmente sofisticada porque en cada test sólo se llama a un método una sola vez; imaginad qué pasaría si quisiéseis hacer un objeto mock para sustituir a un PreparedStatement. Sin embargo, este inconveniente se puede obviar utilizando EasyMock, que es una biblioteca que permite crear objetos mock en pocas líneas y con mucha facilidad.

Cuando se utiliza EasyMock sólo hay que crear un objeto mock llamando a una función de EasyMock, luego registrar qué métodos se van a llamar con qué parámetros y qué valor deben devolver, y luego ejecutar el test y comprobar que se hicieron todas las llamadas esperadas.

Como ejemplo, veamos qué aspecto tiene testTranslate() reescrito usando EasyMock:

@Test
public void testTranslate() throws Exception {
	Downloader downloader = EasyMock.createMock(Downloader.class);
	Translator translator = EasyMock.createMock(Translator.class);
	EasyMock.expect(downloader.download("http://example.com/valeu.html"))
			.andReturn("Valeu!");
	EasyMock.expect(translator.translate("Valeu!", "pt", "en")).andReturn(
			"Thank you!");
	EasyMock.replay(downloader, translator);
	WebPageTranslator pageTranslator = new WebPageTranslator(downloader,
			translator);
	assertEquals("Thank you!", pageTranslator.translate(
			"http://example.com/valeu.html", "pt", "en"));
	EasyMock.verify(downloader, translator);
}

En las dos primeras líneas se crean los objetos mock llamando a EasyMock.createMock() para cada interfaz. En las siguientes se le dice a EasyMock que va a haber llamadas a downloader.download() y translator.translate() con ciertos argumentos, y se le dice qué valores tiene que devolver. En la siguiente línea se le dice a EasyMock que ponga a downloader y translator en modo “replay”; a partir de este punto, cada vez que se haga una llamada a un método de cualquiera de estos dos objetos, EasyMock comprobará si era una llamada que esperaba y devolverá el valor indicado si lo era o emitirá una excepción si no lo era. Finalmente, en la última línea, se le dice a EasyMock que verifique si se han realizado todas las llamadas esperadas.

Así, a simple vista, parece que no hemos ganado mucho usando EasyMock, ya que hemos tenido que añadir cinco líneas al test; sin embargo, si reescribimos todos los tests para utilizar EasyMock podremos deshacernos de nuestros tres dobles para pruebas y reducir la cantidad total de código:

public class WebPageTranslatorTest {
	private Downloader downloader;
	private Translator translator;
	private WebPageTranslator pageTranslator;

	@Before
	public void setUp() {
		downloader = EasyMock.createMock(Downloader.class);
		translator = EasyMock.createMock(Translator.class);
		pageTranslator = new WebPageTranslator(downloader, translator);
	}

	@After
	public void tearDown() {
		EasyMock.verify(downloader, translator);
	}

	private void replay() {
		EasyMock.replay(downloader, translator);
	}

	@Test
	public void testTranslate() throws Exception {
		EasyMock.expect(downloader.download("http://example.com/valeu.html"))
				.andReturn("Valeu!");
		EasyMock.expect(translator.translate("Valeu!", "pt", "en")).andReturn(
				"Thank you!");
		replay();
		assertEquals("Thank you!", pageTranslator.translate(
				"http://example.com/valeu.html", "pt", "en"));
	}

	@Test
	public void doesNotTranslateWhenLanguagesAreEqual() throws Exception {
		EasyMock.expect(downloader.download("http://example.com/valeu.html"))
				.andReturn("Valeu!");
		replay();
		assertEquals("Valeu!", pageTranslator.translate(
				"http://example.com/valeu.html", "pt", "pt"));
	}

	@Test
	public void returnsNullWhenDownloadFails() throws Exception {
		EasyMock.expect(downloader.download("http://example.com/valeu.html"))
				.andReturn(null);
		replay();
		assertNull(pageTranslator.translate("http://example.com/valeu.html",
				"pt", "en"));
	}

	@Test
	public void returnsNullWhenTranslatorFails() throws Exception {
		EasyMock.expect(downloader.download("http://example.com/valeu.html"))
				.andReturn("Valeu!");
		EasyMock.expect(translator.translate("Valeu!", "pt", "en")).andReturn(
				null);
		replay();
		assertNull(pageTranslator.translate("http://example.com/valeu.html",
				"pt", "en"));
	}
}

Como podéis ver, es bastante fácil evitar introducir dependencias excesivamente onerosas en vuestros tests, utilizando inyección de dependencias y dobles para pruebas. Además, con EasyMock, podréis crear objetos mock con mucha facilidad, así que no tenéis excusas para no hacerlo :)

En el siguiente artículo veremos cómo se utilizan dobles para pruebas en lenguajes dinámicos, usando Python para los ejemplos. También estamos llegando al fin de la serie, así que si tenéis preguntas o dudas o lo que sea, hacédmelas llegar y trataré de responderlas en uno o más artículos posteriores.

(Primer artículo, siguiente artículo).

Introducción a la inyección de dependencias

Imaginad que estáis trabajando en el software de una tienda online y queréis escribir tests de unidad para el módulo de pagos:

public class PaymentService {
	private final BancoPepePlatform pasarela;

	public PaymentService() {
		this.pasarela = new BancoPepePlatform();
	}

	public String cobrar(Money cantidad, String titular, String numero,
			int caducidadMes, int caducidadAño, int cvv) {
		Result res = pasarela.charge(titular, numero, caducidadMes,
				caducidadAño, cvv, cantidad);
		return res.isSuccess() ? res.getCode() : null;
	};
}

Pronto os encontraréis con un problema bastante gordo: cada vez que se ejecute uno de los tests estaréis comunicándoos con el Banco Pepe. Si la conexión es lenta, los tests de unidad tardarán mucho tiempo en ejecutarse; si el banco cobra por cada transacción, ejecutar los tests saldrá muy caro (literalmente); si en el servidor del banco tienen un bug o la conexión falla, puede que los tests fallen sin que sea culpa vuestra; si alguien se olvida de usar un número de tarjeta de pruebas, alguien se enfadará mucho. Y esto sólo para empezar.

Los tests de unidad deberían ser rápidos, deberían probar cada componente de forma aislada, y deberían depender del mínimo posible de infraestructura para evitar introducir errores no debidos al componente que estamos probando. Estas tres cosas son todo lo contrario de lo que he escrito en el párrafo anterior; por lo tanto, tenemos que encontrar una solución.

La solución pasa por emplear en los tests de unidad un “simulador” de BancoPepePlatform. Este “simulador” puede funcionar de muchas maneras distintas; la idea es que sea rápido, fiable, y que exponga la suficiente funcionalidad para poder utilizarlo en los tests de unidad de PaymentService. El problema que tenemos ahora es hacer que PaymentService use el BancoPepePlatform de verdad o el simulador, dependiendo de si está ejecutándose el código de verdad o los tests de unidad.

Podríamos intentar usar, por ejemplo, una factoría estática que consulte la configuración y devuelva una instancia de uno u otro tipo:

	public class BancoPepePlatformFactory {
		public static BancoPepePlatform get() {
			if (SystemConfiguration.isTestMode()) {
				return new FakeBancoPepePlatform();
			} else {
				return new BancoPepePlatformImpl();
			}
		}
	}

	public PaymentService() {
		this.pasarela = BancoPepePlatformFactory.get();
	}

No obstante, esta solución tiene sus propios problemas: tenemos que acordarnos de activar el “modo test” en todos los tests de unidad, tenemos que incluir FakeBancoPepePlatform en los binarios de producción de la tienda online aunque no vamos a utilizarlo para nada, y si en un test determinado queremos utilizar un simulador distinto, no podemos.

Una mejor solución para esto es inyectar la dependencia. Es decir, PaymentService no crea la instancia de BancoPepePlatform que necesita, sino que se le proporciona una:

	public PaymentService(BancoPepePlatform pasarela) {
		this.pasarela = pasarela;
	}

A partir de este momento, cada vez que creéis una instancia de PaymentService tendréis que crear también una instancia de BancoPepePlatform y pasársela en el constructor. Por ejemplo, de esta manera en vuestro código de producción:

PaymentService service = new PaymentService(new BancoPepePlatformImpl());

Y de esta forma en los tests de unidad:

PaymentService service = new PaymentService(new FakeBancoPepePlatform());

Si en un test necesitáis una instancia “especial” de BancoPepePlatform es trivial proporcionársela:

PaymentService service = new PaymentService(new BancoPepePlatform() {
	@Override
	public Result charge(String titular, String numero,
			int caducidadMes, int caducidadAño, int cvv, Money cantidad) {
		return null;
	}
});

Ahora tendremos que ir hacia “arriba” en la cadena de dependencias y seguir aplicando el patrón, porque si no, seguiremos teniendo el mismo problema de antes. Por ejemplo, veamos PaymentServlet:

public class PaymentServlet extends HttpServlet {
	private final PaymentService paymentService;

	public PaymentServlet(PaymentService paymentService) {
		this.paymentService = paymentService;
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// ...
	}
}

Al final llegaremos a un punto en el que tendremos código que crea toda la cadena de dependencias del programa:

servlets.add(new PaymentServlet(new PaymentService(new BancoPepePlatformImpl())));

Esta cadena de dependencias puede ser bastante difícil de mantener. Por eso, prácticamente todo el mundo utiliza un “framework” de inyección de dependencias como Spring o Guice, que es el que mejor conozco.

Estos frameworks proporcionan un “inyector”, que es una función que proporciona una instancia de la clase solicitada, inyectando todas las dependencias intermedias. Por ejemplo, con Guice podría obtener una instancia de PaymentServlet de esta manera:

PaymentServlet servlet = injector.getInstance(PaymentServlet.class);

Para inyectar correctamente las clases es necesario marcar sus puntos de inyección. En Guice, esto se hace utilizando la anotación @Inject:

@Inject
public PaymentServlet(PaymentService paymentService) {
	this.paymentService = paymentService;
}

@Inject
public PaymentService(BancoPepePlatform pasarela) {
	this.pasarela = pasarela;
}

Lo más habitual es utilizar un constructor o una o más funciones “setter” como puntos de inyección. Sólo puede marcarse un constructor, pero pueden marcarse todas las funciones que se quiera.

Finalmente, el inyector tiene una configuración, que le indica qué clases inyectar. Esto es necesario si en algún punto de inyección se hace referencia a un interfaz; Guice necesita saber qué implementación se debe inyectar para ese interfaz. Por ejemplo, para que Guice inyecte una instancia de BancoPepePlatformImpl para el interfaz BancoPepePlatform:

public class PaymentModule extends AbstractModule {
	@Override
	protected void configure() {
		bind(BancoPepePlatform.class).to(BancoPepePlatformImpl.class);
	}
}

Esta configuración se le pasa a Guice al crear el inyector:

Injector injector = Guice.createInjector(new PaymentModule());

Guice también permite hacer muchas cosas en su configuración. Por ejemplo, se le puede indicar que sólo debería existir una instancia de una clase:

bind(PaymentServlet.class).in(Scopes.SINGLETON);

O que el objeto a inyectar tiene que venir de una factoría:

bind(PaymentService.class).toProvider(new PaymentServiceProvider());

O utilizar anotaciones para hacer distintas inyecciones para la misma interfaz:

bind(BancoPepePlatform.class).annotatedWith(Paypal.class).to(PaypalBancoPepePlatform.class);

@Inject
public PaypalPaymentService(@Paypal BancoPepePlatform platform) {
	this.platform = platform;
}

Una pequeña nota antes de terminar: si usáis la inyección de dependencias correctamente, necesitaréis usar directamente el inyector solamente una vez. Con él obtendréis una instancia de ShopServer, por ejemplo, que tendrá inyectados todos los objetos que necesite; éstos, a su vez, tendrán inyectadas también todas sus dependencias, y así sucesivamente.

Os aconsejo aprender más sobre inyección de dependencias y echarle un vistazo a la documentación de Guice, que explica todo esto muy bien, porque este patrón de diseño y estas herramientas ayudan muchísimo a hacer que vuestras aplicaciones sean modulares y que los tests de unidad sean más fáciles de escribir.

(Primer artículo, siguiente artículo).

Desarrollo dirigido por los tests

Como su propio nombre indica, el desarrollo dirigido por los tests (“test-driven development”, o TDD en siglas) consiste en escribir primero los tests de unidad y luego escribir el código que hace que estos tests pasen con éxito.

Esta técnica tiene varias ventajas. Por ejemplo, el código escrito de esta manera suele exponer interfaces más limpios, fáciles de usar y desacoplados de la implementación que el código escrito de forma normal. Además, el código suele tener menos errores, y menos funcionalidades añadidas de forma especulativa.

Permitidme explicar este último punto, ya que es menos obvio que los anteriores. Muchas veces, cuando escribimos código, solemos añadir cosas que no necesitamos inmediatamente, pero que suponemos que vendrán bien en el futuro, cuando tengamos que hacer escalar la aplicación o cuando tengamos que añadir nuevas funciones o cuando tengamos que sustituir la base de datos. El problema con este código extra es que... bueno, es código extra: más código que hemos de mantener, más sitios donde pueden esconderse bugs, más espacio que ocupa el programa, más despacio que el programa va, etc. Por lo tanto, es recomendable evitar añadir código de forma especulativa y dejarlo para cuando realmente vayamos a necesitarlo; por desgracia, es una tentación muy difícil de evitar. Sin embargo, al hacer TDD es más fácil concentrarse en escribir sólo el código que hace que los tests pasen ahora mismo y no caer en la tentación.

Por supuesto, el TDD tiene inconvenientes además de ventajas. Por ejemplo, en ocasiones es muy difícil escribir tests para un código todavía inexistente. Otro inconveniente que podéis encontraros es que alguna gente se pasa de lista y cae en la tentación de escribir código que sólo funciona para los tests, en lugar de escribir código que pasa los tests porque es correcto. Si os encontráis con uno de estos, tenéis mi permiso para darles una bofetada (pero no digáis que fui yo quien os lo dio).

En algunos sitios llevan esta técnica un poco más lejos y hacen que una persona escriba los tests y luego otra persona distinta escriba el código. De este modo consiguen que dos personas conozcan el código en lugar de una sola y hacen que sea más difícil introducir bugs (es más difícil que dos personas introduzcan errores que se neutralizan mutuamente que que lo haga una persona sola).

Vamos a ver un pequeño ejemplo de TDD, escribiendo una pequeña implementación de un conjunto en Java. Vamos a comenzar creando la clase MySetTest, donde escribiremos los tests de unidad. También creamos la clase MySet, pero sólo pondremos en ella el esqueleto; sólo lo necesario para que Eclipse no se queje y para poder compilar y ejecutar los tests.

public class MySetTest {
	private MySet<Object> set;
	
	@Before
	public void setUp() {
		set = new MySet<Object>();
	}
	
	@Test
	public void newSetIsEmpty() throws Exception {
		assertEquals(0, set.size());
	}
}

public class MySet<E> {
	public int size() {
		return 0;
	}
}

Como podéis ver, he escrito ya un test de unidad para comprobar que un nuevo conjunto está vacío, y he añadido en MySet el correspondiente esqueleto para el método size(). Vamos a añadir unos pocos tests más:

public class MySetTest {
	private static final Object OBJ1 = new Object();
	private static final Object OBJ2 = new Object();
	
	private MySet<Object> set;
	
	@Before
	public void setUp() {
		set = new MySet<Object>();
	}
	
	@Test
	public void newSetIsEmpty() throws Exception {
		assertEquals(0, set.size());
	}
	
	@Test
	public void addElementIncreasesSizeIfElementIsNew() throws Exception {
		set.add(OBJ1);
		assertEquals(1, set.size());
		set.add(OBJ1);
		assertEquals(1, set.size());
		set.add(OBJ2);
		assertEquals(2, set.size());
	}

	@Test
	public void onlyContainsAddedElements() throws Exception {
		assertFalse(set.contains(OBJ1));
		assertFalse(set.contains(OBJ2));
		set.add(OBJ1);
		assertTrue(set.contains(OBJ1));
		assertFalse(set.contains(OBJ2));
	}
}

public class MySet<E> {
	public int size() {
		return 0;
	}

	public void add(E e) {
	}

	public boolean contains(E e) {
		return false;
	}
}

Nuevamente, fijaos en que mi implementación de MySet sólo contiene lo necesario para que los tests compilen y Eclipse no me llene la pantalla de líneas rojas.

Ahora podemos ejecutar los tests, y veremos que algunos pasarán y otros (la mayoría) fallarán. Nuestra tarea ahora consiste en rellenar el esqueleto de MySet con el código necesario para hacer que los tests pasen. Por ejemplo:

public class MySet<E> {
	private List<E> elems;
	
	public MySet() {
		elems = new ArrayList<E>();
	}
	
	public int size() {
		return elems.size();
	}

	public void add(E e) {
		if (!elems.contains(e)) {
			elems.add(e);
		}
	}

	public boolean contains(E e) {
		return elems.contains(e);
	}
}

Ahora, con sólo ejecutar los tests, sabemos que este código funciona correctamente. Por supuesto, este ejemplo es muy simple, pero imaginad las ventajas que os proporcionaría a la hora de escribir un código más complicado.

Como ejercicio, podéis probar a escribir la función para eliminar un elemento del conjunto: primero escribid un test que compruebe que al eliminar un elemento, el tamaño del conjunto disminuye en 1 si éste estaba en el conjunto, y otro que compruebe que un conjunto no contiene un elemento eliminado. Después, escribid el código que haga que los tests pasen.

La técnica del TDD también es muy útil a la hora de corregir bugs. Para aplicarla, primero escribís un test que falle si el bug existe, y luego modificáis el código para que pase este test. Al hacerlo así, os lleváis dos cosas de regalito: sabéis que vuestro arreglo no afecta al resto de funcionalidades, y sabéis que este bug no reaparecerá en el futuro, ya que ahora tenéis un test que lo detecta.

Hasta ahora hemos visto cómo escribir tests para unidades más bien simples. Por desgracia, casi siempre tenemos que tratar con componentes que dependen de otros componentes, y otras cosas que hacen que escribir tests de unidad pueda ser muy engorroso. En las próximas entregas os explicaré cómo organizar vuestro código para aislar estas dependencias y facilitar la escritura de los tests de unidad.

(Primer artículo, siguiente artículo).

Cómo elegir tests de unidad

En mi artículo anterior os expliqué cómo escribir tests de unidad, pero pasé prácticamente por alto un tema muy importante: ¿qué tests de unidad escribimos? Por desgracia, el párrafo que le dediqué lo explicaba tan mal y de forma tan resumida, que mucha gente se llevó la idea equivocada, así que para solucionarlo aquí va un nuevo artículo dedicado exclusivamente a ese tema.


Por lo general, nuestro objetivo cuando escribimos tests de unidad es comprobar que esta unidad funciona correctamente en los casos normales. Fijaos en que he dicho “comprobar” y no “demostrar”: no queremos una demostración de que la unidad siempre produce una salida correcta con todas las posibles combinaciones de datos de entrada, sino una manera automatizada de comprobar que la implementación funciona bien.

Parece la misma cosa, pero no lo es, y la distinción es importante. Si quisiéramos demostrar que la implementación de un módulo de gestión de clientes es correcta, tendríamos que hacer un catálogo exhaustivo de posibles entradas correctas y de posibles entradas incorrectas, pasarlas todas por el módulo, y comprobar que producen las salidas esperadas. Esto puede suponer mucho tiempo y esfuerzo. Sin embargo, para comprobar que el módulo funciona, no tenemos que matarnos tanto, ya que las pruebas son más informales: grabar un registro, comprobar que se puede leer, modificarlo, comprobar que ahora se lee la versión modificada, borrarlo, ver qué pasa si se intenta obtener un registro que no existe, etc. Mientras que tenemos que asegurarnos de que probamos toda la funcionalidad, estas pruebas no necesitan ser totalmente exhaustivas. De este modo, evitamos que la creación y mantenimiento de los tests de unidad supongan una carga excesiva.

El nivel de detalle al que deberíamos llegar depende del tipo de unidad que queremos probar. Por ejemplo, para una biblioteca que va a ser utilizada por programadores externos, los tests son muy detallados, comprobando diversas entradas válidas y no válidas, etc. Sin embargo, para un módulo interno de una aplicación, los tests sólo cubrirán por lo general los casos que se encuentren en el funcionamiento normal del programa, sin pararse a considerar casos triviales o irrelevantes. En algunos casos no vale la pena escribir tests de unidad; por ejemplo, un “value object” que consista exclusivamente en funciones “get” y “set” triviales no necesita uno.

Los tests de Apache Harmony (una reimplementación libre de las bibliotecas estándar de Java) son un buen ejemplo del primer caso. Por ejemplo, echadle un ojo a ArrayListTest, y veréis que cada test comprueba un método de ArrayList diferente, llamándolo de diferentes maneras, y comprobando que producen los resultados esperados de acuerdo con la especificación.

Para un ejemplo del segundo caso, mirad en Apache Shindig (implementación de referencia de OpenSocial) la clase BasicOAuthStoreTest, que usa unos cuantos datos de ejemplo representativos de un funcionamiento normal del programa para comprobar que las funciones de BasicOAuthStore hacen lo que se supone que deben hacer, pero sin pretender que estas pruebas sean exhaustivas.

Espero que este artículo os haya despejado unas cuantas dudas, y nos veremos en la próxima entrega de la serie :)

(Primer artículo, siguiente artículo).

Cómo escribir tests de unidad

En mi anterior artículo os expliqué varias razones por las que los tests de unidad son importantes, pero no tuve espacio para explicaros cómo crearlos, así que he escrito éste para solucionar ese problema.


Los tests de unidad son programitas que comprueban que una “unidad” funciona correctamente. Una unidad es un grupo de funcionalidad coherente y autocontenido; esto, normalmente, significa “una clase del programa”.

Para escribir los tests de unidad, lo primero que debemos hacer es preguntarnos: “¿cuáles son las propiedades que ha de cumplir esta unidad en todo momento? ¿qué casos he de comprobar, porque los errores suelen ocultarse en ellos?”. Cuando tengamos la respuesta, sólo tendremos que escribir código que compruebe que esas propiedades realmente se cumplen, y que esos casos no producen errores. Tened en cuenta que los tests no tienen que ser exhaustivos, o nos supondrán una carga de trabajo excesiva; he escrito un artículo sobre el tema.

Para escribir tests de unidad se suelen utilizar “frameworks” que proporcionan todo el andamiaje y funciones auxiliares necesarios. Existen muchísimos frameworks libres para casi todos los lenguajes de programación: JUnit (para Java), PyUnit (para Python), JsUnit (para JavaScript), CppUnit (para C++), etc. Como los ejemplos de este artículo están escritos en Java, he decidido emplear JUnit 4.

En el mundo Java existe la convención de poner el código fuente del programa en un directorio llamado “src” y el código fuente de los tests en un directorio llamado “tests”. Además, se configura el sistema de compilación para que los ficheros .class generados al compilar los tests vayan en un directorio especial. De este modo, no se mezclan el código de producción y los tests. En Python y C++ las convenciones son diferentes, pero el objetivo es el mismo: que no se mezcle el código de producción y el código de test.

Dicho esto, vamos a ver el código de la clase para la que quiero escribir los tests de unidad. “MyList” es una implementación de una lista usando un array. Si queréis probar esto en vuestro ordenador y estáis usando Eclipse, cread un proyecto nuevo y poned el código de la clase dentro del directorio “src”.

package org.tarrio.tutorial.unittests;

public class MyList<E> {

	private static final int SIZE_DELTA = 2;

	private Object[] elems;
	private int size;

	public MyList() {
		elems = new Object[SIZE_DELTA];
		size = 0;
	}
	
	public int size() {
		return size;
	}

	public void add(E o) {
		ensureSize(size + 1);
		elems[size++] = o;
	}

	public E get(int index) {
		checkIndex(index);
		@SuppressWarnings("unchecked")
		E ret = (E) elems[index];
		return ret;
	}

	public void set(int index, E o) {
		checkIndex(index);
		elems[index] = o;
	}

	public void remove(int index) {
		checkIndex(index);
		if (index != size - 1) {
			System.arraycopy(elems, index + 1, elems, index, size - index - 1);
		}
		--size;
	}

	private void ensureSize(int newSize) {
		if (newSize > elems.length) {
			Object[] newElems = new Object[elems.length + SIZE_DELTA];
			System.arraycopy(elems, 0, newElems, 0, size);
			elems = newElems;
		}
	}

	private void checkIndex(int index) {
		if (index < 0 || index >= size) {
			throw new IndexOutOfBoundsException();
		}
	}
}

Una vez hecho esto, vamos a comenzar a escribir el test de unidad. Cread un directorio fuente (“source folder”) llamado “tests” y configuradlo para que las clases compiladas vayan a un directorio distinto de “bin” (en Eclipse, pulsad con el botón derecho sobre “tests” y seleccionad Build Path, Configure Output Folder, Specific output folder, y escribid “tests-bin”).

En este directorio fuente cread un paquete con el mismo nombre que el paquete al que pertenece la clase anterior, y dentro del paquete cread una nueva clase llamada “MyListTest”.

Ahora es cuando debéis preguntaros qué propiedades ha de cumplir MyList, para escribir tests para ellas. Por ejemplo, un MyList recién creado está vacío, al añadir un elemento a MyList el tamaño aumenta en uno, al eliminar un elemento de MyList el tamaño se reduce en uno, los elementos de MyList se pueden recuperar en el mismo orden en el que se introdujeron, etc.

Vamos a escribir un test para la primera propiedad: un MyList recién creado está vacío. Para ello, añadid el siguiente método a vuestra clase MyListTest:

	@Test
	public void newListIsEmpty() {
		MyList<Integer> list = new MyList<Integer>();
		assertEquals(0, list.size());
	}

La anotación @Test (org.junit.Test) indica a JUnit que el siguiente método es un test. El método assertEquals (org.junit.Assert.assertEquals) compara un valor esperado con un valor real, y lanza una excepción si no son iguales. Existen muchos otros métodos assertXxxx que sirven para comprobar si una condición es cierta, si dos arrays son iguales, si un objeto es null, etc.

Para ejecutar esto en Eclipse, pulsad con el botón derecho sobre el nombre de la clase y seleccionad Run As, JUnit test. Si todo va bien, deberíais ver un panel con una barra de progreso y un icono, todos de color verde. Podéis cambiar el 0 por un 1 para ver qué ocurre si la condición del “assert” no se cumple.

Ahora que sabemos cómo escribir un test de unidad, vamos a escribir los tests para “al añadir un elemento el tamaño se incrementa en una unidad” y “al eliminar un elemento el tamaño se reduce en una unidad”:

	@Test
	public void addingOneElementIncreasesSizeByOne() {
		MyList<Integer> list = new MyList<Integer>();
		assertEquals(0, list.size());
		list.add(42);
		assertEquals(1, list.size());
		list.add(592);
		assertEquals(2, list.size());
	}
	
	@Test
	public void removingOneElementIncreasesSizeByOne() {
		MyList<Integer> list = new MyList<Integer>();
		list.add(42);
		list.add(592);
		assertEquals(2, list.size());
		list.remove(0);
		assertEquals(1, list.size());
		list.remove(0);
		assertEquals(0, list.size());
	}

Habréis observado que los tres tests que hemos escrito hasta el momento comienzan de la misma forma, creando una nueva instancia de MyList. Esto es código de inicialización común a todos los tests, y sería conveniente extraerlo a un método de inicialización. JUnit nos permite definir un método que se ejecuta antes de cada test, y en el que podemos realizar todas las tareas de inicialización necesarias, marcándolo con la anotación @Before:

	private MyList<Integer> list;
	
	@Before
	public void setUp() {
		list = new MyList<Integer>();
	}
	
	@Test
	public void newListIsEmpty() {
		assertEquals(0, list.size());
	}
	
	@Test
	public void addingOneElementIncreasesSizeByOne() {
		assertEquals(0, list.size());
		list.add(42);
		assertEquals(1, list.size());
		list.add(592);
		assertEquals(2, list.size());
	}
	
	@Test
	public void removingOneElementIncreasesSizeByOne() {
		list.add(42);
		list.add(592);
		assertEquals(2, list.size());
		list.remove(0);
		assertEquals(1, list.size());
		list.remove(0);
		assertEquals(0, list.size());
	}

Como podéis ver, he eliminado la variable “list” de cada test y he creado un atributo privado “list”, que se inicializa en el método “setUp” que está marcado con @Before. Este método se ejecuta antes de cada test, y gracias a él, el atributo “list” siempre contiene una lista recién creada y vacía.

También existe una anotación @After, que sirve para ejecutar un método después de cada test. Como cada test ha de ser independiente de los demás y no debe tener efectos secundarios duraderos, se pueden utilizar los métodos @After para deshacer cualquier cambio de estado que se haya podido producir en los tests o en el método @Before.

A estas alturas, no os debería ser nada difícil escribir tests para “los elementos que se añaden a la lista se pueden recuperar en el mismo orden”, y para cualquier otra propiedad de MyList que se os ocurra. Este es vuestro primer ejercicio.

No os olvidéis de que tenéis que actualizar los tests de unidad cada vez que modifiquéis MyList. Por ejemplo, si añadís el siguiente método a MyList para añadir todos los elementos de otra lista:

	public void addAll(MyList<E> l) {
		ensureSize(size + l.size());
		System.arraycopy(l.elems, 0, elems, size, l.size);
		size += l.size;
	}

Tendréis que escribir al menos un test que compruebe que funciona bien:

	@Test
	public void addAllIncreasesSizeByOtherListsSize() throws Exception {
		MyList<Integer> someList = new MyList<Integer>();
		someList.add(1);
		someList.add(2);
		someList.add(3);
		list.addAll(someList);
		assertEquals(3, list.size());
		someList.add(4);
		list.addAll(someList);
		assertEquals(7, list.size());
	}

Lo añadimos, ejecutamos los tests, y... ¡hala! ¡El nuevo test falla! ¿Qué ha ocurrido? Resulta que tenemos un error en la clase MyList, y el test que acabamos de añadir lo ha detectado. Vuestro segundo ejercicio consiste en buscar y arreglar el error.

Vuestro tercer ejercicio consiste en cambiar la implementación de MyList, de un array a una lista enlazada. Al final del ejercicio, los mismos tests de unidad deberían seguir pasando sin necesidad de modificarlos.

Espero que este artículo os haya resultado instructivo.

(Primer artículo, siguiente artículo).

Introducción a los tests de unidad

Tengo ganas de “evangelizar” sobre buenas prácticas de desarrollo, así que durante los próximos días publicaré una serie de artículos sobre tests de unidad. Aquí va la introducción; los demás artículos serán más técnicos. Espero que la serie os parezca interesante :)


Los tests de unidad (“unit tests” en inglés) son programitas que ponen a prueba una unidad de un programa. Una unidad puede ser una función, una clase, o incluso un módulo entero. Estos programas ejecutan diversas partes de esta unidad con diversos parámetros de entrada, estados internos, etc., y comprueban que ésta produce los resultados correctos.

Los tests de unidad se deberían escribir junto con el código al que prueban, y se deben mantener actualizados de forma que siempre pasen con éxito (ya sea arreglando los fallos que se puedan introducir en la unidad que se prueba, o actualizando el test si el funcionamiento de la unidad ha cambiado). En algunos sitios incluso escriben los tests antes de escribir el código. Lo que hacen es codificar los requisitos en los tests, y así, cuando todos los tests pasan con éxito, saben que el módulo cumple todos los requisitos y además funciona bien.

Podría parecer a simple vista que mantener los tests de unidad al mismo tiempo que el código “de verdad” cuesta más trabajo que, simplemente, no tener tests de unidad. Sin embargo, los tests de unidad proporcionan varias ventajas que compensan con creces su existencia.

La principal es la mayor velocidad de desarrollo. Cuando hacéis un cambio en un programa y no tenéis tests de unidad, la única forma de probarlo consiste en compilar el programa, ejecutarlo, ir hasta la parte que habéis cambiado, hacer la prueba, etc. Sin embargo, con tests de unidad basta con compilarlos y ejecutarlos, y en menos de un minuto tenéis el resultado.

Además, los tests de unidad evitarán que introduzcáis muchos errores, ya que los tests no pasarán con éxito hasta que la unidad a prueba funcione razonablemente bien. Y, si en el futuro descubrís algún error, sólo tenéis que añadir un test que capture ese error, arreglarlo para que el test pase con éxito, y sabréis que no volveréis a introducir ese error en el futuro.

Otra ventaja es que con los tests de unidad podéis estar seguros de que vuestros cambios no tendrán efectos imprevistos. Por ejemplo, algo que se hace a menudo es cambiar la implementación de un módulo sin modificar su interfaz. Si tenéis tests de unidad e introducís algún error en la nueva implementación, alguno de estos tests fallará; cuando todos los tests pasen con éxito, podéis estar razonablemente seguros de que la nueva implementación es correcta. Sin tests de unidad no podéis estar tan seguros.

Otra ventaja importante es que los tests forman parte de la documentación del software. Los Javadoc tienen la molesta costumbre de quedar obsoletos. Tal vez hoy una función de búsqueda devuelve “null” al buscar un elemento que no existe, pero si mañana alguien la cambia para lanzar una excepción y no actualiza el Javadoc, el compilador no protestará y el Javadoc quedará obsoleto. Sin embargo, si hay un test que comprueba que, al pasarle un elemento inexistente, la función devuelve “null”, cuando esta persona haga el cambio el test fallará, así que tendrá que actualizar el test (o dejar la función como estaba). Por tanto, los tests de unidad son una documentación que nunca queda obsoleta.

Por supuesto, los tests de unidad no sirven de nada si nadie les presta atención. En muchas organizaciones tienen políticas que obligan a ejecutar los tests de unidad antes de hacer “commit” (por supuesto, los tests tienen que pasar con éxito). En algunos sitios tienen “compiladores continuos” (“continuous build”), que son máquinas que toman la última versión del software, lo compilan, ejecutan los tests de unidad y avisan si alguno falla. En otros sitios integran los tests de unidad en el sistema de control de versiones, de forma que no se puede hacer “commit” si algún test falla.

En posteriores historias explicaré cómo escribir tests de unidad, cómo usar inversión de dependencias, mocks y objetos falsos para aislar la unidad que queremos probar, y cómo hacer desarrollo dirigido por los tests.

(Siguiente artículo).

Cómo preparar un currículum para EEUU, Reino Unido o Irlanda

Hoy voy a dar un paso más en mi campaña “voy a sacaros a todos de España de una vez”, explicándoos cómo elaborar y mandar un currículum para EEUU, el Reino Unido o Irlanda.

Si pensabais que bastaba con tomar vuestro currículum español, traducirlo al inglés, y mandarlo, estabais completamente engañados: las convenciones sobre qué se debe incluir en un currículum, cómo debe estar estructurado, etc., son diferentes de un país a otro, así que probablemente meteríais la pata si hicieseis eso. Por suerte para el tema que nos ocupa ahora mismo, los currículums (o currículos, o currículunes, según prefiráis) son muy parecidos en EEUU, Reino Unido e Irlanda, así que los mismos consejos os servirán para los tres países.

Por una vez, como este artículo me ha quedado larguíiiiiiisimo y no quiero fastidiarle el lector RSS a nadie, tendréis que pinchar en el título o en el enlace de “leer más” para verlo entero. Así que pinchad, pinchad...

El efecto Menéame

Ayer me publicaron una historia en Menéame y el tráfico subió considerablemente; tanto, que el servidor web se me saturó y tuve que reconfigurarlo.

Para los curiosos, aquí va una gráfica del "efecto Menéame":

La gráfica va desde las 8 de la mañana hasta las 17:59, hora peninsular española. El eje vertical va graduado en peticiones por segundo, y la línea va suavizada tomando la media de los cinco minutos anteriores a cada punto en el eje horizontal.

El tráfico comenzó a subir a las 9:11, que supongo que fue cuando la historia llegó a la portada, y a las 9:21 me di cuenta de que mi servidor estaba saturado. Podéis ver cómo se quedó atascado en las 13 peticiones por segundo hasta las 9:41, que fue cuando por fin arreglé el servidor y todas las peticiones pendientes se sirvieron de repente. No sale en la gráfica por eso del suavizado tomando la media de los 5 minutos anteriores, pero durante ese minuto se recibieron 1669 peticiones -- unas 27 por segundo.

Y a partir de ahí, según quedaba menos gente que no había leído la historia y ésta descendía en la portada de Menéame, el tráfico comenzó a descender hasta las 2 peticiones por segundo...

Si la gente buscara trabajo igual que las empresas buscan empleados

Si la gente buscara trabajo igual que las empresas redactan sus ofertas de empleo, veríamos en los periódicos anuncios como este:

Importante programador Java del sector de las telecomunicaciones busca
empresas senior

Se requiere:

  • Contrato indefinido.
  • Salario mínimo de 40.000 euros anuales.
  • 45 días de vacaciones.
  • Stock-options.
  • Seguro médico.
  • Vehículo de empresa.
  • Almuerzos gratuitos.

Se ofrece:

  • Horas de trabajo a convenir según valía.

Interesados envíen su cuenta de resultados y una foto reciente del/la director/a general a:

Proceso de Selección de Empresa
Apdo 8086
28080 Madrid

Abstenerse ETTs y consultoras.

Impressions after 11 months in the USA

As you know, it's been almost a year since I came to the USA, and as you may suppose, life here is a bit different in many small details from life back in Spain.

For example, treatment of personal data. Companies here assume that, if they have your personal data, it is theirs to sell, trade, etc. In addition, they have always been very careless with them (not so much today) and it was quite common for a credit card company to mail you a letter with a pre-filled request form for you to sign and mail back.

In addition, there is no single identity card system like in Spain, so companies have few ways to verify your identity, and the system all those companies have adopted consists of asking you questions only you can answer, assumedly. Some of those questions are your birth date, your mother's maiden name, or your current address. Of course, as every company asks you the same questions, all of them have that information. And as they mail you prefilled forms including most of that information, it is also available for anyone who gets hold of one of those mailings after intercepting your mail or searching your garbage.

As it is so easy to get one's information and verification systems are so lax, identity theft is an everyday occurrence. It basically consists in the malfeasant getting hold of your birth date and your mother's maiden name and then getting credits and cards and buying stuff in your name, and then not paying any of that, and you get hit with all the debt and fees and charges, and it's years before the problem is solved for good and in the mean time your credit history is hit very badly, etc., etc.

For this reason, something that must never be missing in any household is a document shredder. All letters I get from Mastercard or Capital One offering me credit cards, or from AT&T offering me Internet service, or, in general, anything carrying my name goes to the shredder instead of the garbage bin. In fact, almost all paper I receive goes to the shredder, so it will be all nicely mixed up and more difficult to reconstruct. Of course, my shredder is cross-cut so they won't do the same to me as they did to the US embassy in Iran (their shredders cut in strips, and after the islamic revolution the iranians managed to reconstruct several documents).

A document shredder is very easy to use:

  1. Put a piece of paper in the slot,
  2. look in fascination as the paper is being swallowed by the machine,
  3. look around for any piece of paper I don't need anymore to continue shredding paper.

Seriously, using a document shredder is super addictive. Now I know what the cat who flushed the toilet felt.

Another thing about americans is that they love choosing. For almost anything, they are going to offer you several choices. You go to buy a sandwich and they'll ask you if you want white bread, whole wheat bread, Italian, Indian, if you want jam, peanut butter, if you want coleslaw, lettuce, tuna salad, if you want fries, if you want fruit, ... They almost ask you to give them the recipe for the sandwich.

When I started working in the US I had to sign up for health insurance, and they gave me a choice between five or six options, which were basically divided in two groups: in one, you have to choose your doctor when you start the insurance, and in the other (more expensive) you can choose a different doctor every time. Hospital websites give lots of information about each doctor, with their degrees, professional affiliations, hobbies, etc., so patients can look at them and choose the one they like most. Myself, as I'm very simple, I go with more primal criteria:

“Hello, I'd like to set up an appointment to see a doctor.”
“Which doctor would you like to see?”
“Eh, the one who's available the soonest?”
“Wow, how original.”

And I think I have written enough for now. With a little bit of luck, 11 months from now I'll tell you more things about the USA :)