Archive

Posts Tagged ‘mockito’

Creating an object stream from a JDBC ResultSet

08/14/2014 6 comments

The introduction of  features Stream API and Lambda in Java 8 enables us to make an elegant conversion from a JDBC ResultSet to a stream of objects just providing a mapping function. Such function could be, of course, a lambda.

Basically, the idea is to generate a Stream using a ResultSet as Supplier:

public class ResultSetSupplier implements Supplier<T>{

		private final ResultSet rs;
		private final Function<ResultSet, T> mappingFunction;

		private ResultSetSupplier(ResultSet rs,
                    Function<ResultSet, T> mappingFunction) {
			this.rs = rs;
			this.mappingFunction = mappingFunction;
		}

		@Override
		public T get() {
			try {
				if (rs.next())
					return mappingFunction.apply(rs);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		}
	}

Parameter mappingFunction, which might be a lambda expression, is used to build T instances from a ResultSet. Just like ActiveRecord pattern, every row in such ResultSet maps to an instance of T, where columns are attributes of T.

Let’s consider class City:

public class City{
		String city;
		String country;
		public City(String city, String country) {
			this.city = city;
			this.country = country;
		}
		public String getCountry() {
			return country;
		}
		@Override
		public String toString() {
			return "City [city=" + city + ", country=" + country + ";]";
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((city == null) ? 0 : city.hashCode());
			result = prime * result
					+ ((country == null) ? 0 : country.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			City other = (City) obj;
			if (city == null) {
				if (other.city != null)
					return false;
			} else if (!city.equals(other.city))
				return false;
			if (country == null) {
				if (other.country != null)
					return false;
			} else if (!country.equals(other.country))
				return false;
			return true;
		}
	}

The mapping function for City objects could be a lambda expression like the following:

(ResultSet rs) -> {
                try
                {
                  return new City(rs.getString("city"), rs.getString("country"));
		} catch (Exception e) {
		  return null;
		}}

We have assumed database columns are called city and country, respectively.

Although both PreparedStatement and ResultSet implement AutoCloseable interface, as a  resultSet must be provided to create the object stream, it does make sense to close such resultSet when the stream is closed as well.

A possible approach could be to use a proxy to intercept method invocation on the object stream. Thus, as close() method is invoked on the proxy, it will invoke close() on the provided resultSet. All method invocations will be invoked on the object stream as well, in order to be able to provide all Stream features. That is easy to achieve using a proxy.

Let’s have a look. We will have a proxy factory and a invocation handler:

public class ResultSetStreamInvocationHandler<T> implements InvocationHandler{

  private Stream<T> stream; // proxy will intercept method calls to such stream
  private PreparedStatement st;
  private ResultSet rs;

  public void setup(PreparedStatement st, Function<ResultSet, T> mappingFunction)
  throws SQLException{
    // PreparedStatement must be already setup in order
    // to just call executeQuery()
    this.st = st;
    rs = st.executeQuery();
    stream = Stream.generate(new ResultSetSupplier(rs, mappingFunction));
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable {

    if (method == null)
      throw new RuntimeException("null method null");

    // implement AutoCloseable for PreparedStatement
    // as calling close() more than once has no effects
    if (method.getName().equals("close") && args == null){
    // invoked close(), no arguments
      if (st != null){
        st.close(); // closes ResultSet too
      }
    }

    return method.invoke(stream, args);
  }

private class ResultSetSupplier implements Supplier<T>{

  private final ResultSet rs;
  private final Function<ResultSet, T> mappingFunction;

  private ResultSetSupplier(ResultSet rs, Function<ResultSet, T> mappingFunction) {
    this.rs = rs;
    this.mappingFunction = mappingFunction;
  }

  @Override
  public T get() {
    try {
      if (rs.next())
        return mappingFunction.apply(rs);
    } catch (SQLException e) {
     e.printStackTrace();
    }
    return null;
  }
}

}

Please note how invoke is used to intercept method calls. In case close() is called, close() is called on PreparedStatement as well. For every method called, the corresponding method call is invoked in the stream being proxied.

And the factory:

 

public class ResultSetStream<T>{

	@SuppressWarnings("unchecked")
	public Stream<T> getStream(PreparedStatement st,
            Function<ResultSet, T> mappingFunction) throws SQLException{
		final ResultSetStreamInvocationHandler<T> handler =
                    new ResultSetStreamInvocationHandler<T>();
		handler.setup(st, mappingFunction);
		Stream<T> proxy = (Stream<T>) Proxy.newProxyInstance(getClass().getClassLoader(),
                new Class<?>[] {Stream.class},
                handler);
		return proxy;
	}
}

To put it all together, let’s write a simple test to show usage. Mockito will be used to mock both PreparedStatement and ResultSet to avoid running tests against a real database.


public class ResultSetStreamTest {

	private class City{
		String city;
		String country;
		public City(String city, String country) {
			this.city = city;
			this.country = country;
		}
		public String getCountry() {
			return country;
		}
		@Override
		public String toString() {
			return "City [city=" + city + ", country=" + country + "]";
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result + ((city == null) ? 0 : city.hashCode());
			result = prime * result
					+ ((country == null) ? 0 : country.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			City other = (City) obj;
			if (!getOuterType().equals(other.getOuterType()))
				return false;
			if (city == null) {
				if (other.city != null)
					return false;
			} else if (!city.equals(other.city))
				return false;
			if (country == null) {
				if (other.country != null)
					return false;
			} else if (!country.equals(other.country))
				return false;
			return true;
		}
		private ResultSetStreamTest getOuterType() {
			return ResultSetStreamTest.this;
		}
	}

	private String[][] data = new String[][]{
			{"Karachi", "Pakistan"},
			{"Istanbul", "Turkey"},
			{"Hong Kong", "China"},
			{"Saint Petersburg", "Russia"},
			{"Sydney", "Australia"},
			{"Berlin", "Germany"},
			{"Madrid", "Spain"}
		};

	private int timesCalled;
	private PreparedStatement mockPST;
	private ResultSet mockRS;

	@Before
	public void setup() throws SQLException{
		timesCalled = -1;
		mockRS = mock(ResultSet.class);
		mockPST = mock(PreparedStatement.class);

		when(mockRS.next()).thenAnswer(new Answer<Boolean>() {

			@Override
			public Boolean answer(InvocationOnMock invocation) throws Throwable {
				if (timesCalled++ &gt;= data.length)
					return false;
				return true;
			}
		});

		when(mockRS.getString(eq("city"))).thenAnswer(new Answer<String>() {

			@Override
			public String answer(InvocationOnMock invocation) throws Throwable {
				return data[timesCalled][0];
			}
		});
		when(mockRS.getString(eq("country"))).thenAnswer(new Answer<String>() {

			@Override
			public String answer(InvocationOnMock invocation) throws Throwable {
				return data[timesCalled][1];
			}
		});

		when(mockPST.executeQuery()).thenReturn(mockRS);
	}

	@Test
	public void simpleTest() throws SQLException{

		try (Stream<City> testStream = new ResultSetStream<City>().getStream(mockPST,
				(ResultSet rs) -> {try {
					return new City(rs.getString("city"), rs.getString("country"));
				} catch (Exception e) {
					return null;
				}})){

			Iterator<City> cities = testStream.filter(
					city -> !city.getCountry().equalsIgnoreCase("China"))
					.limit(3).iterator();

			assertTrue(cities.hasNext());
			assertEquals(new City("Karachi", "Pakistan"), cities.next());

			assertTrue(cities.hasNext());
			assertEquals(new City("Istanbul", "Turkey"), cities.next());

			assertTrue(cities.hasNext());
			assertEquals(new City("Saint Petersburg", "Russia"), cities.next());

			assertFalse(cities.hasNext());
		}

	}

}

Download full source code on Github.

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: ,

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: ,

Mockear métodos estáticos, privados, finales y mas con PowerMock

01/09/2012 3 comments

La inyección de mocks o stubs en tests unitarios es una técnica muy extendida, debido a que  permite eliminar las dependencias externas de las clases a testear, con lo que se simplifica enormemente la creación del entorno de test. Existen varias herramientas, como Mockito, que facilitan enormemente esta tarea al proporcionar métodos sencillos de creación (y verificación) de mocks y stubs. Otra opción que goza de gran aceptación es EasyMock.

Pero, en cuanto a la inyección de dependencias, tanto si se realiza la inyección directamente mediante constructores o setters, o se usan herramientas específicas como, por ejemplo, Guice, en muchas ocasiones aparece el problema de que el diseño apropiado no es el mas adecuado para la inyección de mocks: si para crear un mock de un método estático habría que crear algún tipo de wapper o adaptador, tampoco se pueden usar mocks para métodos privados, a menos que se cambiase la visibilidad a protected y se corriesen los tests contra una clase que, extendiendo de la clase a testear, proporcionase métodos públicos que, de esa manera, permitiesen acceso a los protegidos de la clase base. Pero, en ambos casos, se requiere modificar el código y, además, no se prueba exactamente la clase que se desea.

Estos son algunos de los motivos por los que puede ser útil dedicar algo de tiempo a trastear con PowerMock. Otra razón de peso es que para usar PowerMock no es necesario modificar los tests existentes: PowerMock está diseñado para extender Mockito y EasyMock, en lugar de para reemplazarlos. Como entornos de test soporta JUnit y TestNG. A continuación se muestra una pueba de concepto usando PowerMock para extender Mockito en un entorno de test JUnit4.

Se parte del supuesto de que se desea testear un código que se acaba de escribir y que usa un método estático de otra clase. Si el método no fuese estático, se podría, simplemente, inyectar un mock de la clase de la que se depende sin mas problemas.

La clase con la que se mantiene la dependencia:

public class LegacyCode {
public static String getMessage(){
 return new String("Esto es una castaña (estática)");
 }
public String getAnotherMessage(){
 return new String("Esto es una castaña");
 }
}

La clase que se desea testear:

public class MyClass {
public String methodToTest (){
 return LegacyCode.getMessage();
 }
public String methodToTestNotStatic(LegacyCode legacyCode){
 return legacyCode.getAnotherMessage();
 }
}

Y el test:

public class MyClassTest {
 @Test
 public void testLegacyCode(){
 // Creamos un mock para LegacyCode usando Mockito
 LegacyCode mockLegacyCode = mock(LegacyCode.class);
 // Le indicamos lo que debe devolver en este test en concreto
 when(mockLegacyCode.getAnotherMessage()).thenReturn("Lo que diga el mock");
// Instanciamos y comprobamos el mensaje devuelto
 MyClass myClass = new MyClass();
 System.out.println(myClass.methodToTestNotStatic(mockLegacyCode));
 verify(mockLegacyCode, times(1)).getAnotherMessage();
 }
 }

En realidad, testear no se testea nada, el objetivo es simplemente ver que el mock funciona. Y, en efecto, al ejecutar el test se obtiene la cadena Lo que diga el mock  en lugar de Esto es una castaña.

Nada nuevo hasta aquí para los que ya usan estas técnicas. Pero, ¿ que ocurre al testear el método methodToTest de la clase ? En este caso, al llamar a un método estático, no se puede inyectar un mock tal y como se acaba de ver.

Aquí es donde entra PowerMock. Se puede usar PowerMock para crear el siguiente test, donde en este caso se incluyen los imports para que se pueda apreciar como PowerMock (PowerMockito en este caso) tan sólo extiende, pero no sustituye, a Mockito:

 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(LegacyCode.class)
 public class MyClassTest {
 @Test
 public void testLegacyCode(){
 MyClass myClass = new MyClass();
 LegacyCode mockLegacyCode = mock(LegacyCode.class);
 when(mockLegacyCode.getAnotherMessage()).thenReturn("Lo que diga el mock");
 System.out.println(myClass.methodToTestNotStatic(mockLegacyCode));
 verify(mockLegacyCode, times(1)).getAnotherMessage();
 }
 @Test
 public void testMockLegacyCode(){
 mockStatic(LegacyCode.class);
 when(LegacyCode.getMessage()).thenReturn("Esto ya es otra cosa");
 MyClass myClass = new MyClass();
 System.out.println(myClass.methodToTest());
 }
 }

Nota: aunque no aparezca a simple vista en la documentación de PowerMock, es necesario incluir en el classpath javassist.

En este caso se ha creado un mock para la clase completa, aunque tambien podría crearse un mock parcial, sólo para el método estático.

La anotación @RunWith debe añadirse siempre para usar PowerMock. Echando un vistazo puede apreciarse que se ha escogido el PowerMockRunner para JUnit 4.

Para crear mocks de clases con métodos estáticos, debe añadirse además la anotación @PrepareForTest, indicando la clase para la que se creará el mock, en este caso LegacyCode.class. Por lo demás, la única diferencia es que, en lugar de llamar al método mock de Mockito, se llama al mockStatic de PowerMockito.

Ejecutando los tests se obtiene como salida:

Lo que diga el mock
Esto ya es otra cosa

Lo que diga el mock, en lugar de Esto es una castaña, como ya se había visto anteriormente, y Esto ya es otra cosa, en lugar de Esto es una castaña (estática), que es lo que devuelve el método estático.

En resumen, PowerMock añade a Mockito o EasyMock, usados conjuntamente con JUnit o TestNG, la posibilidad de crear mocks para métodos estáticos (clase completa o sólo métodos), métodos privados e incluso constructores. De hecho, la posibilidad de crear mocks para métodos estáticos y constructores roza el terreno de la inyección de dependencias en sí mismo.

 

%d bloggers like this: