Páginas

lunes, 7 de octubre de 2019

Ejemplo de Verify FindOne() de MongoCollection de Jongo con JUnit y Mockito

Planteamiento y código

Este ejemplo está elaborado con Java 1.5, JUnit 4.12, Mockito 1.9.5, MongoDB driver 3.10.2, Jongo 1.3.0 y la base de datos MongoDB server 4.0.

Se muestra cómo preparar una prueba para un módulo de acceso a base de datos. Lo más remarcable es la forma de acceder a verificar que el método FindOne(query) es invocado una vez.
El siguiente módulo accede a una base de datos MongoDB, para buscar un usuario y comprobar si su contraseña coincide con una dada que contiene el objetoUsuarioBean. 

El módulo que accede a la base de datos y es el objeto de la prueba. O sea el SUT (Subject Under Test)

UsuarioColeccion.java

import org.jongo.Jongo;
import org.jongo.MongoCollection;
import com.mongodb.DB;
import com.mongodb.MongoClient;

public class UsuarioColeccion {
    private DB db;
    private MongoCollection mongoCollection;
   
    public MongoCollection getMongoCollection() {
      return mongoCollection;
    }
   
    public void setMongoCollection(MongoCollection mongoCollection){
        this.mongoCollection = mongoCollection;
    }

    @SuppressWarnings("deprecation")
    public UsuarioColeccion()  {
        db = new MongoClient().getDB("UsuariosDB");
        mongoCollection = new Jongo(db).getCollection("Usuarios");       
    }
        

    public boolean buscarUsuarioContrasena(UsuarioBean bean){ 
            String query="{_id: '"+bean.getNombreUsuario()+"'}";   
            UsuarioBean usuario = 

                 getMongoCollection().findOne(query).as(UsuarioBean.class);      
            if (usuario==null)
                return false;
            else           
                return usuario.getContraseña().equals(bean.getContraseña());
    }
}


El código del bean

UsuarioBean.java

import org.jongo.marshall.jackson.oid.Id;

@SuppressWarnings("deprecation")
public class UsuarioBean {
  
    @Id
    private String nombreUsuario;
    public String getNombreUsuario() {
        return nombreUsuario;
    }

    private String contraseña;
    public String getContraseña() {
        return contraseña;
    }

    public UsuarioBean() { }
    public UsuarioBean(String nombreUsuario, String contraseña) {
        this.nombreUsuario = nombreUsuario;
        this.contraseña = contraseña;       
    }
}
 


Se construye una prueba unitaria que no accede a la base de datos, este acceso se comprobará en las pruebas de integración. La prueba unitaria verifica que se ejecuta el método FindOne() de MongoCollection de Jongo una sola vez cuando se accede a buscar un documento en la base de datos. 

El módulo de prueba unitaria es

UsuarioColeccionTest.java

import java.net.UnknownHostException;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import org.jongo.FindOne;
import org.jongo.MongoCollection;

import estratecno.Mongo.UsuarioBean;
import estratecno.Mongo.UsuarioColeccion;

public class UsuarioColeccionTest {
   
    UsuarioColeccion coleccionUsuarios;
    UsuarioBean bean;
    MongoCollection mongoCollection;
   
    @Before
    public void before() throws UnknownHostException {
       coleccionUsuarios = new UsuarioColeccion();   
       bean = new UsuarioBean("Pepe","abcd");
       mongoCollection = Mockito.mock(MongoCollection.class);
    } 


    @Test
    public void cuandoBuscaUsuarioUsaFindOne(){
        String query="{_id: '"+bean.getNombreUsuario()+"'}";
        FindOne findResult = Mockito.mock(FindOne.class);
        Mockito.doReturn(findResult).when(mongoCollection).findOne(query);
        coleccionUsuarios.setMongoCollection(mongoCollection);
        coleccionUsuarios.buscarUsuarioContrasena(bean);       
        Mockito.verify(mongoCollection, Mockito.times(1)).findOne(query);       
    }

}
 

Asuntos remarcables del ejemplo:

  • Aunque UsuarioColección crea su propia MongoCollection en el constructor,  la prueba unitaria mockea una MongoCollection que le inyecta a UsuarioColeccion. Esta MongoCollection que suplanta a la real, permite hacer la prueba sin acceder a la Base de Datos Real. La inyección se hace con:       
        coleccionUsuarios.setMongoCollection(mongoCollection);
  • Para decirle al suplantador que la MongoCollection auténtica llama al método findOne()  se codifican las expectativas de Mockito:
        FindOne findResult = Mockito.mock(FindOne.class);
        Mockito.doReturn(findResult).when(mongoCollection).findOne(query);


         En este caso la expectativa hace uso de un suplantador de FindOne llamado findResult. 
         findResult es necesario para crear la  expectativa como  tipo  que  devuelve  el  método 
         findOne(query).
  • La forma de verificar que se llama a findOne() una sola vez es:
        Mockito.verify(mongoCollection, Mockito.times(1)).findOne(query);