Archive

Posts Tagged ‘testing’

Is your code thread safe?

The last weeks I started to considerate about concurrency testing. I wrote an utility that tries to test if your code is thread safe or not.

When you repeat an experiment many times, the result tends to be the expected

This means that if you throw a die one time, we can not know what result is going to happen, but if we do it thousands of times, we will know that each result is going to happens 1/6 of the times.

In less words, lets repeat this many times at the same time and then check if it is fine or not. The problem here is, how to do it at the same time?.

The utility has 2 classes, ConcurrenceHelper and Task. Task is an interface that you need to implement to provide ConcurrenceHelper the job to do. ConcurrenceHelper will trigger all the tasks “at the same time”.

This is the interface:

public interface Task {

	void execute();
	
}

And this class will trigger all the tasks in different threads. Onces all the threads have executed the tasks, the main thread will leave the method (it means that this method is synchronous).

import java.util.concurrent.CountDownLatch;

public class ConcurrenceHelper {

	public void triggerTasks(final int nThreadsPerTask, final Task ... tasks) throws InterruptedException{
		final CountDownLatch waitForThreadsEnd = new CountDownLatch(nThreadsPerTask*tasks.length);
		final CountDownLatch waitToStart = new CountDownLatch(nThreadsPerTask*tasks.length);
		for(final Task task : tasks){
			for(int i=0;i<nThreadsPerTask;i++){
				final String THREAD_NAME = task+"-"+i;
				new Thread(new Runnable() {
					@Override
					public void run() {
						try {
							waitToStart.countDown();
							// Threads are waiting until countDown=nThreadsPerTask*tasks.length
							waitToStart.await();
							task.execute();
						} catch (InterruptedException e) {
							throw new RuntimeException(THREAD_NAME+" can not wait any more o_O", e);
						}finally{
                        	waitForThreadsEnd.countDown();
                        }
						
					}
				}, THREAD_NAME).start();
			}
		}
		// The main thread is waiting until countDown=nThreadsPerTask*tasks.length
		waitForThreadsEnd.await();
		// At this point all threads have executed the task
	}
	
}

And now lets do some testing:


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import java.util.List;
import java.util.Vector;

import org.junit.Test;

public class SamplesTest {

	private final ConcurrenceHelper concurrence = new ConcurrenceHelper();
	private final int CONCURRENCE_TASKS = 10000;
	
	@Test
	public void vectorIsThreadSafe() throws InterruptedException{
		final List<Long> list = new Vector<>();
		concurrence.triggerTasks(CONCURRENCE_TASKS, new Task() {
			@Override
			public void execute() {
				list.add(System.currentTimeMillis());
			}
		});
		System.out.println("Value "+list.size());
		assertEquals(CONCURRENCE_TASKS, list.size());
	}
	
	@Test
	public void notThreadSafeClass() throws InterruptedException{
		final NotThreadSafeClass obj = new NotThreadSafeClass();
		concurrence.triggerTasks(CONCURRENCE_TASKS, new Task() {	
			@Override
			public void execute() {
				obj.i++;
			}
		});
		System.out.println("Value "+obj.i);
		assertNotEquals(CONCURRENCE_TASKS, obj.i);
	}
	
	private class NotThreadSafeClass{
		protected int i;
	}
	
}

We are testing one class that we know that is thread safe (Vector) and other one that is not thread safe (NotThreadSafeClass). It is easier to test that one class is thread safe than checking that is not thread safe. The test vectorIsThreadSafe() will be successfull the 100% of the times, but notThreadSafeClass() will not be successfull the 100%. For that reason, to prevent you to have randomly testing errors, make the testing oriented to check that is thread safe (by the way, is what we really want to test).

To prevent concurrency problems, try to make the classes as much inmutables as possible.

Advertisements

Crea tus propios Matchers

Si no sabes lo que es un Matcher, pasa por la siguiente direccion antes de leer mi articulo:

http://mockito.googlecode.com/svn/branches/1.5/javadoc/org/mockito/Matchers.html

A menudo testeando necesitamos hacer algún tipo de checkeo que Mockito no ha implementado por nosotros, pero afortunadamente nos ofrecen una forma de hacerlo. A groso modo, las implementaciones de matchers de mockito consisten en comprobar que “el metodo se ha invocado con cualquier parametro” o que “se ha invocado con exactamente unos parametros definidos por ti”. Pero a veces no nos interesa ni tanto, ni tan poco.

Por ejemplo, uno de los problemas que podemos encontrar en mysql es que en las fechas no se guardan los milisegundos. Como consecuencia, la fecha que vamos a introducir es diferente que la que recogeremos una vez persistida, pues habremos insertado una fecha que en milisegundos es 123456789234 y se recogera 123456789000. Asi que cuando queramos matchear que la fecha que hemos introducido es la misma que la persistida, tendremos un fallo. A lo mejor, queremos hacer que no se matchen los milisegundos. Vamos a ello:

Debemos heredar de la clase ArgumentMatcher, que nos obligara a implementar la funcion matches. Este metodo es el que ejecuta el mockito cuando matchea. Como argumento, tiene un Object que es el objeto que realmente se ha invocado:


public class DateMatcher extends ArgumentMatcher<Date>{

private Date dateBeforePersist;

public DateMatcher(Date dateBeforePersist){
this.dateBeforePersist=dateBeforePersist;
}

@Override
public boolean matches(Object argument) {
Date persistedDate=(Date)argument;
//Comparamos en segundos en vez de milisegundos
return persistedDate.getTime()/1000==dateBeforePersist.getTime()/1000;
}

}

Una vez hecho esto, donde antes teniamos:

Date fecha=new Date();
//Comprueba que se ha invocado someMethod con exactamente esa fecha (milisegundos incluidos)
verify(mock).someMethod(eq(fecha));

Pondremos:

Date fecha=new Date();
//Comprueba que se ha invocado someMethod con esa fecha en segundos
verify(mock).someMethod(argThat(new DateMatcher(fecha)));

Categories: Desarrollo, Testing Tags: ,

Automatización de Tests: QTP (Quick Test Professional) Vs Selenium

Interesante comparativa entre herramientas de automatización. Personalmente, no he probado QTP, y no he podido enredar con Selenium todo lo que me hubiera gustado, pero la siguiente comparativa inclina claramente la balanza. Sobre todo en los casos en que se está introduciendo la automatización de tests. En los demás casos, el hecho de estar ya trabajando con una herramienta concreta aporta un peso que podría nivelar o incluso volcar la balanza hacia el otro lado.

Quick Test Professional Vs Selenium | Execute Automation.

Categories: Desarrollo, Testing Tags: , , ,

Errores comunes al hacer pruebas de software de nuestro código

Los desarrolladores cada vez estamos más concienciados de la importancia de las pruebas de software. Pero no podemos pasar por alto la calidad de estas pruebas, ya que podemos caer en errores no contemplados sin darnos cuenta. No es suficiente con hacer un par de tests y pensar que todo está todo correcto porque nuestra aplicación pasa esos tests, es importante pararse a pensar si cómo hemos planteado las pruebas es la forma correcta para detectar errores reales del código.

A continuación se mostrarán algunos errores comunes a la hora de hacer tests extraídos de un interesante post en Dzone sobre testing.

Test unitarios

Es sencillo probar una clase de utilidad con sólo llamar a todos los métodos de la clases, pasando valores y comprobando si el resultado es el esperado. Aquí caemos en el error de hacer pruebas del estilo: 1+1=2 y 2+1=3. Pero no hacemos, por ejemplo, pruebas de casos limites como cuando los valores son null o si se provoca una excepción, estas quedan muchas veces fuera de nuestras pruebas.

El uso de Mocks

Si nos encontramos en el caso de que queremos probar la capa de servicio, el DAO lo solemos simular manualmente. Un terrible error que puede llevar a confusiones en los test, para hacer este trabajo deberíamos usar un Mock que nos permite hacer pruebas más cercanas a la realidad para eso están creados.

Podemos elegir entre varios framework como Mockito o EasyMock, entre los más conocidos. Pero tener cuidado de elegir el correcto, el exceso de simplicidad o, por el contrario, el de complejidad nos puede traer algún que otro quebradero de cabeza.

Test de integración

En los test de integración cubrimos las diferentes piezas que trabajan en conjunción de nuestra aplicación. Una de ellas es la capa DAO, con la que intentamos validar el funcionamiento conjunto con los parámetros de entrada, las conexiones de base de datos y si sus respectivas queries son las correctas.

Solemos caer en el error de no usar datos que se correspondan con los reales, por lo que nuestros test pueden ser trucados con parámetros de entrada que reciban de la base datos información errónea o incompleta haciendo malabarismos manualmente para comprobar que el test es correcto. También es importante poder cargar datos de tal forma que podamos volver de nuevo al estado inicial.

Test funcionales

Después de probar buena parte de nuestro código técnicamente, no debemos olvidar los bugs funcionales. A través de los test funcionales podemos detectar esos errores. Aunque tengamos la percepción de que son difíciles y costosos de mantener más lo es hacer eso manualmente.

Selenium es una gran framework para grabar este tipo de test con el navegador, aunque caemos en el error de sólo hacerlos ahí. Selenium trackea los componentes HTML, por lo que si cambiamos algo de la página romperemos el test inmediatamente y no necesariamente es porque esté mal. Una opción más robusta es usar API WebDriver que proporcionar una interfaz de programación alternativa para testear con una API orientada a objetos.

Otra cosa que tenemos que tener en cuenta es dejar también en los test cada elemento o dato en su estado inicial. Si en un test hacemos login, debemos recordar cerrar sesión para no interferir en posteriores test o al contrario.

Artículo sacado de GenbetaDev

Categories: Desarrollo, Testing Tags: ,
%d bloggers like this: