Archivo de la categoría: Artículos Técnicos

Otros tipos de inyección de dependencias

No es la primera vez que hablo en este blog sobre inyección de dependencias, el patrón que nos permite pasar todas las dependencias que una clase necesita en el constructor en vez de como argumentos en métodos o utilizar clases estáticas.

En el caso de Java, donde últimamente paso la mayoría de mi tiempo, contamos con Spring y Guice como las maneras más conocidas de inyectar dependencias, veamos un ejemplo de Spring.

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ClassWithDependencies {
    private final DependentClass dependentInstance;

    public void doSomethingWithDependency(){
        dependentInstance.doSomething();
    }
}

@Component
public class DependentClass {
    public void doSomething(){
        System.out.println("Doing something")
    }
}

En este ejemplo, con las anotaciones @Component de Spring y @RequiredArgsConstructor de Lombok (un pre-procesador que nos permite agregar setters, getters y constructores a Java) podemos definir ClassWithDependencies como una clase que recibe DependentClass como parámetro del constructor, y luego operar sobre ella.

En artículos anteriores hemos hablado de otros sistemas como el de ASP.net vNext o incluso crear el nuestro propio. Creando un motor de inyección de dependencias con C#

Es importante destacar que en este ejemplo concreto, la inyección construye una nueva instancia de la clase cada vez que se inyecta, siendo la más sencilla de las opciones de inyección.

Una instancia por ejecución (Singleton)

Sin embargo, podemos personalizar aún más el tipo de inyección que hacemos. Volviendo a nuestro ejemplo anterior, supongamos que DependentClass contiene información de la máquina (memoria, procesador, etc) en la que se ejecuta, y por tanto no cambiará a lo largo de la vida de nuestra aplicación.

En este caso, una nueva instancia de cada clase sería innecesario o incluso costoso, dependiendo del tipo de inyección, para lo cual, en la definición del componente, especificamos qué tipo de inyección queremos

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ClassWithDependencies {
    private final MachineContext machineContext;

    public void doSomethingWithDependency(){
        machineContext.getProcessor();
    }
}

@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class MachineContext {
    public String getProcessor() {
        return "Intel";
    }
}

Comparemos esto con definir un patrón singleton de manera manual:

public class ClassWithDependencies {
    private final MachineContext dependentInstance;

    public void doSomethingWithDependency(){
        MachineContext.getInstance().getProcessor();
    }
}

public class MachineContext {
    private static MachineContext instance;

    public String getProcessor() {
        return "Intel";
    }

    private MachineContext() {
    }

    public static MachineContext getInstance(){
        if(instance == null){
            instance = new MachineContext();
        }
        return instance;
    }
}

La principal diferencia de usar Singleton en inyección respecto al singleton estándar que podemos ver en el ejemplo anterior es con inyección de dependencias tenemos las ventajas de singleton y mantenemos la capacidad de probar nuestro sistema, ya que en una prueba de ClassWithDependencies podríamos simular o utilizar un mock de MachineContext (por ejemplo si queremos probar cómo se comporta nuestra aplicación en distintos contextos).

Una instancia por petición (Request)

Una variante de Singleton especialmente para web, ocurre cuando el contexto depende de la petición o la sesión. Para este ejemplo, tenemos una función que se dedica a llevar un registro de las excepciones, y queremos, para cada excepción, registrar además el Id del usuario al que le ocurrió la excepción.

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GlobalExceptionHandler {
    private final Request request;

    public void handleException(Exception ex){
        logger.error(request.getUserId(), ex.getStacktrace())
        machineContext.getProcessor();
    }
}

@Component
@Getter
@Setter
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class Request {
    private String userId;
}

Este formato nos permite rellenar la clase Request en la capa del controlador de de nuestra aplicación, y en la otra directamente preguntar por el estado, sin necesidad de tener que pasar el objeto request a lo largo de toda la cadena de llamadas hasta la captura de esta excepción.

Con ello, evitamos que nuestras clases tengan una referencia al objeto únicamente por tener que pasarlo a la siguiente capa, se simplifica el número de parámetros que manejamos y podemos referirnos al contexto siempre que lo necesitemos.

Conclusiones

En este artículo hemos repasado inyección de dependencias de manera tradicional y además hemos visto las ventajas de utilizar construcciones como Singleton y Request.

Y tú, usas estas construcciones cuando desarrollas aplicaciones?

Anuncios

Scala desde la perspectiva de C# y JavaScript, tercera parte

En los artículos anteriores de esta serie, veíamos una pequeña introducción a Scala, y hacíamos una kata para comprobar que habíamos entendido la sintaxis. En este artículo veremos dos construcciones del lenguaje que resultan bastante interesantes, llamadas traits y case classes.

Traits

Podemos entender los traits como una mezcla entre interfaces y clases abstractas, ya que podemos definir un contrato como haríamos con una interfaz, y por otra parte podemos definir también una implementación.

A diferencia de Java, Scala nos permite implementar varias traits, y podemos utilizarlas para agregar características adicionales a nuestro código. Veamos un ejemplo.

En este caso vamos a definir una clase base llamada Employee, que tiene un salario, y luego vamos a definir varios traits, algunos solamente con valores, y otros con pequeñas comprobaciones.

  • El trait Temporary calcula el mes final del contrato
  • El trait Authority nos permite saber si un empleado tiene gente a su cargo
  • El trait Remote nos permite establecer una localización y una zona horaria
  • Finalmente, el trait InOffice nos permite establecer un despacho.

Con estos cuatro traits podemos componer las clases que forman a nuestros empleados, donde tenemos a Developer, a Manager y a Intern:

Como vemos en el ejemplo, podemos utilizar los traits para definir características adicionales a nuestras clases, y podemos también agregar lógica dentro de las mismas, mezclando los conceptos de interfaz y clase abstracta.

Case classes

La otra cara de la moneda son las Case Classes, que podemos encontrar cuando definimos jerarquías, pero sobre todo las podemos encontrar cuando tenemos un número específico de entidades y lo que realmente cambia es lo que hacemos con ellas. Recuperando el mismo caso de empleados, becarios y managers, vamos a redefinirlo como Case Classes:

En este caso hemos simplificado la manera de definir los diferentes datos, y solamente utilizaremos la fecha inicial para Dev y Manager, y el tiempo total de estancia para Intern. En este caso, podemos asumir que nuestro conjunto de datos está fijo.

Sin embargo, ¿qué pasaría si necesitáramos agregar información de nóminas a nuestra aplicación? Si recurriéramos a la herencia, deberíamos implementar un método “salary” o similar, para cada una de las clases, sin embargo, como estamos usando “case classes” podemos crear un único método que las compruebe todas, y se comporte de manera consistente:

En este caso, el método nos devolverá distintos resultados en función de la clase que estemos aplicando y los datos que contenga la misma, permitiendo una separación entre las clases que contienen los datos de los métodos para manipularlos.

Este enfoque tiene sus inconvenientes, y es que si tenemos que agregar un nuevo tipo de dato (por ejemplo, External) tendremos que cambiar todos los métodos auxiliares para soportar el nuevo caso, así que se reduce a elegir en función de las necesidades de nuestro proyecto.

Conclusiones

Construcciones como Case Classes o Traits nos permiten establecer restricciones de una manera sencilla, las traits nos permiten mezclar conceptos de interfaces y clases, y las case classes nos permiten separar los datos de nuestra clase de las transformaciones que hacemos con los mismos.

En C# tenemos a nuestra disposición los métodos de extensión, con los que podemos lograr un comportamiento similar que con las case classes, y que hemos visto con anterioridad en este artículo “Clases abstractas VS interfaces + métodos de extensión“.

En el próximo artículo de la serie veremos más construcciones y, como siempre, más ejemplos.

Para más información:

Importando el calendario de nuestro evento favorito

El próximo 27 y 28 de noviembre estaré un año más en el Codemotion, un evento que se celebra en Madrid reúne comunidades de todo tipo y del que hemos hablado en otros artículos de años anteriores.

En ellas desarrolladores de .NET, Java y la JVM, Ruby, Python, JavaScript, Objective-C, Swift, PHP y otros, se reunen para enseñarnos lo mejor de todos los mundos. Yo ya tengo mi entrada, si no tienes la tuya ya estás tardando

Sin embargo hay algo que sigo sin entender. Al igual que en otros eventos, tenemos disponible la agenda completa en la web, y probablemente el primer día nos entregarán una copia EN PAPEL que acabará en una papelera varios días después del evento, si no lo perdemos antes.

No sería mucho más conveniente poder tener el calendario oficial del evento en un formato que lo pudiera entender nuestro Google Calendar, Outlook, iCal o cliente que utilicemos, y poder usar nuestro móvil para orientarnos por el evento? Pues bien, eso es lo que he hecho, y es lo que veremos en este artículo:

Primer paso, obtener los datos

Para obtener los datos originales tenemos muchas maneras. Una de ellas es utilizar un servicio como Kimono que nos permite crear una API REST a partir de una página ya existente, lo cual nos puede resultar muy útil para extraer información.

Otra opción consiste en investigar un cómo, y qué datos carga la página. En el caso de Codemotion, la agenda se carga de manera asíncrona, así que tras investigar el panel de red de Chrome podemos ver un fichero en formato JSON que contiene, para nuestro disfrute, la agenda completa a nuestra disposición, así que, misión cumplida.

Segundo paso, comprender el formato de salida

Para poder generar un fichero que sea compatible con los diferentes clientes de email, una de las opciones es utilizar el formato icalendar, que define un evento de la siguiente manera:

BEGIN:VEVENT
SUMMARY:Document like a hero using Asciidoctor
DTSTART:20151127T160000Z
DTEND:20151127T164500Z
DESCRIPTION:In 2013, the Spring team decided to migrate the Starting Guides on spring.io ...
END:VEVENT

Analicemos los diferentes componentes, dejando de lado las cabeceras begin y end del evento:

  • Summary: Título que se mostrará en la cita del calendario
  • Dtstart: Fecha y hora de inicio de la cita en la zona horaria UTC, en el siguiente formato: Año Mes Día (T) Hora Minutos Segundos (Z)
  • Dtend: Fecha y hora de fin de la cita, en el mismo formato anteriormente comentado
  • Description: Detalles del evento

Si hemos utilizado el calendario de manera corporativa echaremos de menos temas como invitados, alarmas, etc, aunque todos ellos forman parte del estándar y podemos utilizarlos sin problemas. Para reunir varios eventos en un fichero iCalendar hemos de establecer unas cabeceras y un pie de página de la siguiente manera:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
...
END:VCALENDAR

En este código, definimos nuestro fichero iCalendar, la versión del mismo, y el identificador del generador (que en este caso lo he tomado directamente del ejemplo de la wikipedia). Cerramos el fichero con el marcador End.

Con esta información, ya podemos generar nuestro calendario.

Tercer paso, generar el calendario

Para este ejemplo, como utilizaba un fichero en formato json, me pareció mucho más sencillo utilizar JavaScript y Node.js para generar el fichero ics.

Una de las cosas que nos aporta JavaScript, es que, al ser dinámicamente tipado, podemos abstraer la consola en un objeto creado por nosotros, y asignarlo o no a la consola en función de nuestra necesidad.

Como detalle a tener en cuenta está el uso de saltos de línea, ya que hemos de utilizar \n, de otra manera, se generará una nueva línea en el fichero de texto resultante y tendremos un error al importarlo.

Además, aunque parezca obvio, podemos tener más de un evento en un mismo fichero ics.

Cuarto paso, probarlo

Por último, y no por ello menos importante, es necesario confirmar que nuestro calendario se ha generado correctamente, para lo que podemos utilizar servicios como iCalendar validator. Finalmente recomiendo utilizar alguna aplicación de escritorio (como iCal en Mac) para hacer un par de importaciones y comprobar que todos los eventos se generan correctamente.

Conclusiones

Podemos generar un calendario utilizando el formato ics y teniendo una fuente de origen de datos. Si nuestra fuente está en formato json, podemos utilizar JavaScript de manera sencilla para movernos por el mismo, y generar nuestro fichero de resultado, que, por cierto, tienes disponible públicamente en Github.

Yo ya tengo mi calendario, y tú?

Enlaces adicionales:

Scala desde la perspectiva de C# y JavaScript, segunda parte

En la primera parte de esta serie vimos una primera introducción a Scala como lenguaje de programación definiendo algunas características de su sintaxis. En esta segunda parte pasaremos a la práctica utilizando una Code Kata.

En las artes marciales, se denomina kata a una representación, individual o colectiva, de un conjunto de movimientos. En disciplinas como el Karate se suelen enseñar en exhibiciones. El objetivo de las mismas es repetir los movimientos una y otra vez hasta que los mismos surjan de manera natural.

En programación, denominamos code kata a una definición de un problema relativamente simple, que resolvemos una y otra vez cuando estamos aprendiendo un lenguaje o una técnica como TDD. En este caso elegiremos una kata llamada Karate Chop, que define lo siguiente:

Dada una lista ordenada y un número, devolver la posición del mismo en la lista o -1 si no se encuentra, utilizando búsqueda binaria para ello.

El objetivo en este caso era ver si podía aprender lo mínimo necesario para poder escribir una solución a esta Kata utilizando Scala y utilizando la sintaxis de programación estructurada o orientada a objetos a la que estoy acostumbrado. Tras varias iteraciones agregando tests y condiciones, llegué al siguiente resultado:

Para hacer las pruebas se suele usar un framework como ScalaTest, o recurrir a JUnit o TestNG de Java, que, como hemos mencionado anteriormente, son compatibles. En mi caso me limité a crear una pequeña función auxiliar que simplemente comparaba el resultado de la función y escribía por pantalla si había discrepancias:

Finalmente, para comprobar que el código “funciona” he usado el siguiente conjunto de casos de prueba:

Escribiendo esta función aprendí varias cosas sobre Scala:

  • No necesitamos escribir el tipo de dato, ya que tenemos las palabras reservadas var para variables y val para objetos inmutables. Scala infiere el tipo de dato en tiempo de compilación por nosotros de la misma manera que lo hace C#, de manera que tenemos un sistema de tipos sólido y más sencillo de escribir.

  • Como curiosidades de sintaxis, el tipo de respuesta de una función lo definimos al final de la misma, en la definición de los parámetros también se declara primero el nombre y después el tipo, y el acceso a arrays se realiza mediante paréntesis en vez de corchetes.

#Conclusiones

Lo más importante que podemos ver en este ejemplo, es que no necesitamos cambiar nuestra manera de programar para comenzar a usar Scala, y que podemos ir agregando características funcionales de lenguaje a nuestro código poco a poco.

En el siguiente artículo de la serie volveremos a la teoría, retomando por donde lo habíamos dejado, viendo características como las Case Classes, el reconocimiento de patrones, y otros ejemplos de código, más funcionales que podemos encontrar en GitHub.

Mientras tanto, aquí están algunos enlaces sobre coding katas que he usado para hacer este artículo:

Scala desde la perspectiva de C# y JavaScript, primera parte

Hace unos días me estuvieron hablando de las ventajas y maravillas de Scala, un lenguaje multiparadigma con un fuerte enfoque funcional que funciona sobre la máquina virtual de Java, es 100% compatible con el mismo en ambas direcciones, y también por ello es multiplataforma.

Tras echarle un vistazo a algo de documentación me pareció suficientemente interesante como para intentar escribir algo de código, y algunos artículos, usando la perspectiva de otros lenguajes como C# o JavaScript.

Historia

Scala es un lenguaje que llegó a nosotros desde el mundo académico por parte de Martin Odersky en el año 2003. Odersky, quien había trabajado anteriormente en javac, creó el lenguaje combinando ideas de diferentes lenguajes funcionales.

Como curiosidad, destacar que en sus primeras versiones estuvo disponible tanto para la plataforma Java como para .NET, aunque el soporte para el último fue perdiendo popularidad con los años y desde 2012 no está soportado oficialmente.

No es ni mucho menos el único lenguaje funcional que nos encontramos para la JVM, ya que existen alternativas como Haskell o Clojure, pero sin duda Scala es uno de los más potentes y veteranos, usado actualmente por empresas como LinkedIn, Twitter o FourSquare.

¿Qué tiene de especial?

Sintaxis simple

Basta con echar un vistazo a un “Hola mundo” para ver que la sintaxis es algo más simple que en java:

object HelloWorld {
	def main(args: Array[String]){
		println("Hello world")
	}
}

Si guardamos este código en un fichero HelloWorld.scala, podemos compilarlo usando scalac HelloWorld.scala y ejecutarlo ejecutar utilizando el comando scala -classpath . HelloWorld, con lo cual solamente necesitamos un bloc de notas (o Sublime Text/Atom/Vim/Emacs) y una línea de comandos para empezar a jugar.

Una de las cosas que primero nos llama la atención es la palabra reservada object. Al usar esta palabra reservada definimos la clase como Singleton y el compilador nos genera una instancia con el nombre de la clase, de tal manera que podríamos llamar al método HelloWorld.main desde cualquier punto de nuestra aplicación. Usando la palabra reservada class podemos utilizar las clases a las que estamos acostumbrados en otros lenguajes como C# y Java.

Todo es un objeto

A diferencia de Java, Scala no tiene el concepto de tipos básicos, como pudieran ser enteros, floats, o booleanos, sino que todos ellos son objetos, de la misma manera que lo podemos encontrar en C#. Como objetos, se pasan por referencia y no por valor, y simplifican tanto la lectura como la escritura, ya que no tenemos que estar trabajando con conceptos como boxing o unboxing.

Sin embargo, Scala va un paso más allá, y las funciones también pueden ser objetos, con lo cual las podemos pasar por referencia a otras funciones. Si hemos trabajado anteriormente con JavaScript, esto nos sonará mucho a los callbacks de métodos asíncronos, donde podemos pasar una función por parámetro, y si venimos de C# podemos conseguir el mismo efecto utilizando Delegates.

Veamos un ejemplo:

object Timer {
	def oncePerSecond(callback: () => Unit){
		while(true) {callback(); Thread sleep 1000 }
	}

	def callback(){
		println("Ping..."))
	}

	def main(args: Array[String]){
		oncePerSecond(callback)
	}
}

En este ejemplo podemos ver cómo utilizamos un callback que ejecutamos una vez cada segundo. Como curiosidad de sintaxis podemos ver que al llamar al método sleep no usa la sintaxis Thread.sleep(1000) a la que podíamos estar acostumbrados, que también es válida, lo que se denomina sintaxis infija.

Clases y constructores.

Siguiendo con la filosofía de no escribir más código del necesario, podemos definir nuestras clases en Scala directamente con el constructor en la definición de la misma, como muestra el ejemplo:

class Complex(real: Double, imaginary: Double){
	def re() = real
	def im() = imaginary
}

En este caso en la definición de la clase definimos además dos métodos que nos permiten recuperar el resultado de los valores. En caso de que necesitemos más de un constructor, Scala lo soporta mediante el uso de “this”, como muestra el siguiente artículo: Alternate constructors in Scala

La opción de definir los parámetros del constructor era algo que originalmente estaba previsto para C# 6, pero que se retiró de la especificación por su complejidad, aunque es posible que la veamos en C# 7 como muestra el hilo en CodePlex

Es importante destacar que Scala, a diferencia de JavaScript, es estáticamente tipado, con lo cual el tipo de dato de respuesta del método re, será de tipo Double, y se calculará en tiempo de compilación. Podríamos además, quitar los paréntesis tanto a los métodos re como im, y obtendríamos propiedades como las de C#

Resumen y siguientes pasos

Scala es un lenguaje multiparadigma, esto es, que podemos seguir programando de manera orientada a objetos, o podemos incorporar alguna de las características de la programación funcional. Utiliza la JVM y es compatible con Java en ambas direcciones.

En la segunda parte de esta serie, veremos características como las Case Classes, el reconocimiento de patrones, y algunos ejemplos de proyectos reales que podemos encontrar en github. Mientras tanto, aquí están algunas fuentes que he usado para hacer los artículos de esta serie, así como algunos vídeos recomendados:

Kanwal, mi propio Trello dentro del firewall

He de reconocer que soy un gran fan de Trello, un tablero de Kanban personalizable que me permite organizar mi agenda, mis objetivos personales, los viajes, las charlas, mis proyectos y los regalos de navidad, entre otros.

Sin embargo, para uso profesional he descubierto que muchas empresas que no permiten guardar información relacionada con proyectos en servicios en la nube, y para ello he creado un pequeño clon de Trello llamado Kanwal, para poderlo utilizar de manera segura dentro el firewall.

Para poder empezar a utilizarla necesitaba, como mínimo, las siguientes características:

  • Aregar listas
  • Agregar elementos a las listas
  • Borrar elementos de las listas

Características como mover un elemento de lista o editar elementos pueden ser muy chulas, aunque entrarán en la siguiente versión.

Con esa máxima tocaba escoger armas, y en mi caso fueron dos que ya había utilizado anteriormente:

  • Knockout.JS: Un framework MVVM muy sencillo y ligero que me permite realizar data-bindings de manera rápida y fácil
  • Bootstrap: Un framework CSS que me permite dar una estructura y un aspecto básicos a la web.
  • Yeoman: Una herramienta que nos permite crear proyectos con diferentes frameworks de manera rápida y sencilla.

Con las armas escogidas, tocaba ponerse manos a la obra, y un par de horas después la aplicación (si es que podemos llamarla aplicación) tenía este aspecto: Espartano, básico, pero es todo lo que necesito para empezar a trabajar:

kanwall-v1

La arquitectura es muy simple:

Una tarea:

  • Es una cadena de texto simple

Una lista:

  • Es un Viewmodel que contiene un título y una lista de tareas.
  • Contiene un método para agregar tareas, para borrarlas y para renombrar la lista, pasando a un sencillo “modo edición”.
  • Contiene una referencia al método guardar del viewmodel global.

El viemodel global:

  • Es una lista de listas.
  • Contiene Métodos para guardar y cargar los datos de local storage.

Como curiosidad, el nombre original era Kan-Wall (de Kanban firewall), aunque gracias a la corrección de Google descubrí que el nombre (con una L) correspondía a una región de Australia, así que así se ha quedado.

Le puedes echar un vistazo a la aplicación en rlbisbe.github.io/kanwal y ver el código fuente en github.
Si estás interesado en ayudar, envíame una pull request!

Have fun!

Las 5 maneras en las que hago pruebas con ASP.NET

Al desarrollar aplicaciones en ASP.NET, tener un buen conjunto de pruebas es la diferencia entre encontrarte un fallo en desarrollo o en producción, así de sencillo. Las pruebas no evitan todos los errores, pero al menos nos permite que los caminos críticos se mantengan estables. Veamos de qué manera podemos probar nuestras aplicaciones ASP.net

1. Pruebas Unitarias

En una prueba unitaria probamos habitualmente los métodos y el comportamiento de una clase, aunque, por supuesto, no es necesario probar TODOS los métodos (getters y setters, por ejemplo, a menos que tengamos algun tipo de lógica de validación dentro de los mismos).

En una prueba unitaria, además, es importante que mantengamos aislada la clase a probar, de tal manera que todos los servicios o clases externas puedan ser simulados mediante mocks o clases de test específicas. Para estos mocks podemos recurrir a librerías como Moq.

Backend

Personalmente he utilizado tanto MSTest, NUnit como XUnit, estando más familiarizado con el primero ya que lo uso a diario. En general cada framework tiene sus características que lo hacen más interesante, aunque todo se reduce a encontar aquel con el que más cómodos nos sintamos.

Frontend

Si nuestra página contiene lógica de lado de cliente (por ejemplo, si estamos diseñando una SPA con Angular, Knockout o React) se hace prácticamente imprescindible el uso de tests. Para ello podemos recurrir a frameworks como QUnit, Jasmine o Mocha, herramientas que nos permiten establecer unas condiciones para crear tests, así como proporcionarnos un entorno de ejecución para ejecutar las mismas.

Estas herramientas, además, se pueden integrar con Visual Studio y también con Team Foundation Server/Visual Studio Online mediante la extensión Chutzpah que podemos agregar a nuestra solución.

2. Pruebas de integración

En una prueba de integración probamos la interacción entre diferentes módulos de nuestra aplicación, y en este caso el objetivo es asegurarnos que ciertos caminos funcionan correctamente entre las diferentes capas de la misma. Una prueba de aceptación no tiene por qué cubrir todo el sistema, sino que puede cubrir tan solo una parte del mismo.

Un ejemplo podría ser comprobar que el valor que llega a un controlador, pasa por la capa que valida la lógica de negocio de ese valor y finalmente devuelve una respuesta correcta, simulando la inserción en la base de datos.

Mientras más fuertes sean nuestras pruebas de integración entre componentes del sistema, más facilidad tendremos para encontrar y corregir posibles errores de regresión que no hayamos encontrado en pruebas unitarias, ya que, habitualmente, es en la interacción en donde pueden surgir más problemas inesperados.

3. Pruebas de UI

Una de las cosas que más problemas nos puede dar es no saber si los caminos críticos de nuestra web están funcionando correctamente, y para ello, la única manera de poder asegurarnos al 100% es mediante una prueba que simule un usuario navegando por la página. Para este cometido podemos utilizar Selenium, que nos permite grabar el comportamiento de un usuario en nuestra página y posteriormente reproducirlo, así como escribir este comportamiento en C# y ejecutarlo como si de un test de integración se tratara.

4. Pruebas de carga

¿Qué pasa cuando la aplicación recibe 1000 usuarios de golpe? ¿Soportará un “efecto menéame?. Benditos problemas, pero problemas al fin y al cabo. Si estamos trabajando en una solución que tenga que soportar cierta carga (prensa, bancos, redes sociales…) las pruebas de carga deben formar parte de nuestro plan de pruebas, ya que nos permitirán estresar el sistema y poder descubrir otro tipo de errores. Una de las herramientas para realizar estas pruebas de carga es JMeter del proyecto Apache, que nos permite además personalizar la salida de estas pruebas y poder ver los resultados como listas o como gráficas.

5. Tests exploratorios

Este tipo de pruebas resulta bastante interesante y ya hemos hablado de ellas en alguna ocasión ya que mezclan intuición y experiencia adquirida, para intentar encontrar nuevos fallos, errores o escenarios que se escapen del uso habitual del sistema (los denominados también “Corner cases”).

La ventaja de estos tests es que nos aportan un mayor conocimiento sobre el sistema, aunque pueden resultar difíciles de realizar o incluso tediosos, aunque hemos de pensar que no estamos haciendo el trabajo de la máquina, sino intentando ir un poco más allá.

Conclusiones

Aunque los test exploratorios pueden caer fuera del ciclo habitual de test de una tarea, no es conveniente dejarlos fuera, ya que nos pueden aportar mucho conocimiento sobre una herramienta, sobre todo si tenemos que trabajar con código heredado.

Estas son solo cinco opciones que personalmente uso o he usado en mi día a día, existen más sabores y tipos de tests, aunque el objetivo de todos es el mismo, asegurar la fiabilidad del código que estamos poniendo en producción.

¿Y tú, qué pruebas haces? Déjame un comentario o hablemos en @rlbisbe