Ir al contenido

Etiqueta: microsoft

Single Responsibility Principle

Ya hace un tiempo llevo trabajando en una empresa en el sector financiero, en la cual como toda empresa de su envergadura el stack de tecnologías y aplicaciones que poseen es diverso. Y como comprenderan eso tarde o temprano nos llevaba tener que trabajar con legacy code, y las serie de retos que estos involucran. Más de una vez, he tenido que atajar métodos de más de 1000 líneas de código que tenían como objetivo extornar algún monto, grabar log, etc. Esto se vuelve un dolor se cabeza al querer realizar pruebas unitarias para que sean parte del pipeline que se ejecuta en un ambiente de integración y despliegue continuo.

Este problema pone en evidencia la importancia de desarrollar teniendo siempre en mente la utilización de patrones de diseño. Esto me lleva a tratar en este post el primero de los principios de SOLID, siendo los principios que lo componen no los únicos que existen, pero si un marco de buenas prácticas en el desarrollo de software que nos permite asegurar un nivel de calidad en lo que desarrollamos.

Single Responsability Principle representa la “S” en SOLID, este principio entre otras cosas nos indica que los métodos que desarrollamos deben poseer una sola reponsabilidad y por lo tanto un sólo motivo para cambiar. Cuando nos referimos a responsabilidad, esta puede tomar la forma de las siguiente maneras:

Tipos de responsabilidad
  • Grabar en una base de datos, archivo de texto o cualquier otro medio de persistencia que se desee.
  • Realizar un log del método que se está consumiendo y/o también de los errores que puedan ocurrir.
  • Validar la información ingresada al método.
  • Lógica de negocio.

En lineas generales, debemos buscar que el código que desarrollemos tenga el menor acoplamiento posible y la única manera de conseguirlo es definiendo adecuadamente las responsabilidades. Una buena manera de probar que tanto acoplamiento posee nuestro código es cuantos test unitarios es necesario desarrollar para poder coberturarlo al 100%, es muy usual que si nuestro método desarrollado tiene muchas responsabilidades, el poder realizarle pruebas unitarios se va a volver algo extremadamente completo y tedioso. Para poder probar este patrón de diseño, vamos a reformular código teniendo en cuenta las consideraciones antes mencionadas.

La aplicación que vamos a refactorizar nos permite obtener el cálculo de ratio para la realización de la contratación de una poliza, tenemos un método de más de 100 lineas de código que posee distintas responsabilidades, tal como podemos ver en la siguiente imagen:

Código a refactorizar
  1. Grabación del log cuando inicia la llamada al método.
  2. Lectura de un archivo de texto y conversión a un objeto.
  3. Validación de la data obtenida.
  4. Lógica de negocio.
  5. Persistencia de la información obtenida en un archivo de texto.
  6. Grabación del log cuando finaliza la llamada al método.

Como podemos ver, es necesario reformular el método para que cumpla con los requerimientos descritos por este patrón. Esto lo realizaremos extrayendo ciertas responsabilidades del método principal. El primero nos permitirá realizar el grabado de logs:

Método para grabar logs

Luego, desarrollaremos un método para leer el archivo de texto, el cual debe poder retornar la entidad que le pasemos, por lo tanto es debe ser genérico.

Método para leer de un archivo de texto y retornar una entidad

Además, es necesario extraer el grabado de la persistencia en un método, este también debe aceptar como variables de entradas genericos.

Grabado de la persistencia

Finalmente, quedando el método del siguiente modo:

Método refactorizado

Notese que también he separado en un método distinto las validaciones de las polizas de vida.

Espero que les ayude a entender un poco más este principio, así mismo comentarles que este es el primer post de los principios que componen SOLID. Como siempre, dejo el video del desarrollo de esta post y el link al repositorio en github.

REPO: GITHUB

2 Comentarios

Llamar un Mock Object dos veces con distintos resultados

Recientemente en el trabajo nos enfrentamos a un escenario cuando estabamos creando los test unitarios de un proyecto. Usando Moq como librería para el mocking queriamos que al llamar a un mismo método en el repositorio obtengamos distintos resultados por cada llamada. Ya en un post anterior he tratado un tema similiar a este con test unitarios, pero en los escenarios más simples es sólo necesario realizar un llamado obtener el resultado desarrollar cierta lógica de negocio con este resultado y evaluar los aserciones en el test.

Me parecio interesante desarrollar un poco más este tema y por eso hago este post, en el les explicaré un poco sobre las distintas opciones que tenemos para poder obtener distintos resultados al llamar a mock object con Moq, siendo una de estas opciones “SetupSequence” que es un overload al método setup que existe en esta librería, lo que podría generar un problema es que este overload es relativamente reciente, dado que recién se a incorporado como parte de la librería el 20 de junio del 2019. Y la otra opción es el uso de una estructura de datos como las queue o colas.

Para el desarrollo del post, me valdré del mismo proyecto que trabajamos en el post pasado, simplemente he añadido nuevos método en la capa de aplicación y en el repositorio y nuevos test unitarios.

APLICACION

Nuevo método en la capa de aplicación

Este método, como ven simplemente llama dos veces al mismo método del repositorio, con distintos parametros de entrada y retorna la concatenación de ambos resultados.

REPOSITORIO

Nuevo método en la capa de repositorio

Como ven, en el repositorio también se ha creado un nuevo método acá se está intentando simular que se llega a una base de datos, pero por fines prácticos se está devolviendo el nombre completo para todas las llamadas. Veamos los nuevos test unitarios desarrollados.

TEST

Uso de SetupSequence

Como pueden ver, con el uso de “SetupSequence” es posible realizar más de “Returns” los cuales, se van devolviendo conforme se van llamando, de manera tal que en el primer llamado desde la capa de aplicación, se devuelve “walberth”, y en el segundo “angela” y finalmente, se retorna la concatenación.

Uso de queue (Colas)

La otra forma de conseguir el mismo resultado, es valiendonos del uso de colas, como saben esta estructura de datos es del tipo FIFO (first in, first out), de modo que cada ves que llamemos a nuetro moq, y su objeto de retorno es del tipo Queue va a devolver los objetos de este modo.

Espero que les sirva de ayuda como hemos podido resolver este escenario, tal ves con un caso tan común, pero cuando ocurre puede que nos tome un par de horas ver la forma de darle solución. Como siempre, dejo el video del desarrollo de esta solución y los links a github.

REPO: GITHUB

Saludos.

1 comentario

Unit Test y Mocking en NetCore

Cuando empezamos a desarrollar, sea el lenguaje que nos adopte incialmente no solemos tener en consideración los test unitarios y mucho menos el mocking. Si nos dedicamos a este mundo del desarrollo, tarde o temprano vamos a tener que llegar a saber para que sirven y como implementarlos, y de esto de lo que busco escribir un poco hoy.

TEST UNITARIOS

Los test unitarios son secciones de código de escribimos, cuyo objetivo es probar el funcionamiento y funcionalidad de otros métodos que hayamos desarrollado. Es importante tener claro el concepto de atomicidad al querer realizar un test unitarios, dado que el método a probar que se ha desarrollado debemos intentar que posea una única responsabilidad, de manera tal que nuestros test unitarios puedan ser atómico.

MOCKING

Cuando nos referimos a mocking, debemos tener claro que se tiene que llevar a cabo con una prueba unitaria, y lo que nos permite es abstraer el método que queremos probar de otras dependencías que no se están probando. De tal manera, podemos aislar nuestro test unitario y conseguir que sean realmente atómicos.

En el ejemplo que llevaremos a cabo, explicare como implementar un test unitario en Net Core 2.2, usando una librería para poder aplicar mocking en nuestro test. Para conseguir esto, usaremos XUnit para el test unitaio y Moq para el mocking. Es importante recalcar que existen otras opciones y que los conceptos que se aplicarán en la demo, puedes tranquilamente extrapolarse a alguna otra librería que se quiera usar.

Para empezara crear nuestro proyecto, se tiene la siguiente estructura en un proyecto demo:

Distribución del proyecto demo
Nuget utilizados en el test unitario

La arquitectura no es lo importante en esta demo, pero basicamente tenemos una capa de presentación (aplicación consola), una capa de aplicación y una de repositorio, en esta última se debe tener acceso a la base de datos. Las pruebas se dividirán de la siguiente manera:

  1. Para explicar los test unitarios se tiene un método en la capa de aplicación un método que recibe el nombre y apellido de una persona y lo regresa concatenado, teniendo varientes si se ha ingreso el nombre o el apellido en vacio.
  2. Probaremos el mocking simulando que estamos accediendo al repositorio y desde este a una base de datos en donde obtenemos un listado de nombres de personas.
Capa de aplicación
Capa de repositorio

En el proyecto de test unitarios, se crearon los siguientes test unitarios:

  • El primero prueba el escenario ideal del método que desarrollamos, notemos que en la primera parte de nuestro test, estamos preparando la información, liego consumimos el método desarrollado y finalmente evaluamos el resultado con los assert que nos brinda xunit.
  • En el segundo test unitario, probamos el escenario en el que a nuestro método no se le proporcione la información necesaria. Se sigue el mismo formato con la organización de los pasos para las pruebas (preparar la información, llamar al método y finalmente evaluar los resultados).
  • Para realizar la prueba del mocking, es importante realizar la inyección de dependencia del repositorio en nuestra aplicación, dado que lo que buscamos con el mocking es poder simular el acceso en este repositorio, Luego, en el test creamos el mock con la interfaz de nuestro repositorio, le indicamos en “Setup” con una expresión lambda el método que vamos a probar, y en este punto podríamos proporcionale la información que sea necesaria para consumir este método de ser esto necesario y finalmente le indicamos lo que va a retornar, para conseguir esto hemos debido crear un objeto del mismo tipo que retorna nuestro método y indicarlo dentro de “Returns”. Finalmente, le pasamos nuestro mock al construtor de nuestra aplicación y llamamos al método a probar.
Inyección de dependencia
Mocking usando moq en NetCore

Finalmente, corremos nuestros test unitarios y tenemos el siguiente resultado:

Como podemos ver, lo importante del test unitario es poder realizar pruebas atómicas del código que escribimos y con esta finalidad quitarle la responsabilidad como obtener objetos que escapan a lo que buscamos probar (como conexiones a base de datos o otros métodos). Y con esta finalidad nos apoyamos del mocking, existen muchas cosas más que se pueden llevar a cabo con Xunit, e incluso más con Moq, ambas librerías usadas para esta demo, Más adelante realizaré más post en los cuales detallo un poco las características de ambas, espero que encuentren útil el post, les dejo el video y el link de github del proyecto realizado.

REPO: GITHUB

Saludos.

Dejar un comentario