Compartir con la comunidad todo aquello que pueda resultar útil para las personas interesadas en software development, software craftsmanship, agile, leadership, etc
Monday, January 23, 2023
Riesgos en la gestión de proyectos
Mejor práctica para escribir un riesgo
Debido a la <CAUSA(s)> puede ocurrir el <RIESGO o EVENTO_INCIERTO>, lo que provocaría el <EFECTO(s)> en el proyecto.
Enlaces
Notas de testing de aplicaciones .NET con xUnit y Moq
Intro a las pruebas de código
- Dos aspectos a tener en cuenta cuando creas tus pruebas de código son: Organización y Optimización.
- Prácticas de diseño de software que impactan en la mejora de las pruebas: SRP, DIP
- Las pruebas van en un proyecto independiente del código que se quiere probar.
- Con las pruebas de código podemos intentar asegurar que tu proyecto hace lo que se espera de él.
- Organización de las pruebas: Separar totalmente el código de producción del código de pruebas.
- Carpeta /src para proyectos de código para producción
- Carpeta /test para proyectos de código para pruebas
- Cómo implementar las pruebas: AAA
- Arrange (Aprovisiona/Organiza): Para crear escenario de prueba
- Act (Actúa): Ejecutamos el código que queremos probar
- Assert (Afirma): Comprobar los resultados obtenidos vs los esperados.
- Las pruebas se lanzan a través de:
- El explorador de pruebas
- La terminal --> dotnet test
- Live Testing (ejeución en segundo plano) --> Con Visual Studio edición Enterprise
- Convención para los nombres: NombreDelMétodo_QueDeberíaDevolver_Condiciones
- Sumar_ShouldBe5_IfA3AndB2()
- Par_ShouldBeTrue_IfA2()
- Dividir_ShouldBe4_IfA8AndB2()
- Dividir_ShouldThrowDivideByZeroException_IfA8AndB0()
xUnit.net
- Con xUnit.net podemos realizar pruebas de código mediante hechos y teorías.
- Fact (Hecho): Una prueba de código única que te permite probar unas condiciones concretas.
- Theory (Teoría): Pruebas de código múltiples. Cada ejecución de una teoría se lleva a cabo de manera independiente.
- Para que las pruebas sean útiles, no solo hay que probar el resultado, sino todos los caminos lógicos que pueda seguir el código. Esto incluye las excepciones y los retornos nulos.
- Una aserción no es más que una comprobación que, en caso de no cumplirse, lanza una excepción. xUnit.net trae un conjunto de asersiones, pero también se puede agregar nuevas a través de librerías.
- Alguna veces es necesario preparar el entorno para las pruebas, por ejemplo incluir ciertos archivos en una carpeta. Podemos hacer esto a través del propio constructor de la clase para preparar las pruebas, e implementar IDisposable para limpiar los recursos una vez que hayamos terminado. Todo este código auxiliar que estamos usando en el constructor lo podemos sacar a una clase independiente a través de los Fixture (Accesorios).
- In xUnit, a test fixture is all the things we need to have in place in order to run a test and expect a particular outcome. Existen 2 tipos de Fixture:
- De clase --> IClassFixture<T>
- De colección --> ICollectionFixture<T>
- Con el accesorio de clase (ClassFixture) vamos a poder compartir funcionalidad entre todas las ejecuciones de las pruebas de una clase.
- La forma de indicar a mi clase de prueba que necesita un accesorio es la siguiente:
- Para tener un código auxiliar que sea transversal a la ejecución de varias clases de prueba usamos un accesorio de colección (ICollectionFixture<T>). Con una colección agrupamos diferentes clases de prueba dentro de una misma ejecución.
- xUnit.net permite agrupar/organizar pruebas. Esto lo logramos a través de los rasgos, es decir, a través del uso del atributo [Trait].
- Los rasgos nos van a permitir filtrar dentro del explorador de pruebas
- Tambien podemos crear rasgos personalizados. Con estos podemos agrupar bugs, agrupar historias de trabajo, tipos de prueba, funcionalidad, etc.
- xUnit.net ofrece la posibilidad de registrar los logs que nos interese, y se añadirán al resultado de la prueba, independientemente de si esta pasa o no.
Simulaciones con Moq
- Un Mock es un objeto simulado: fake object, dummy object, simulated object...
- Moq es un framework de mocking.
- Los mock (objetos simulados) nos van a permitir sustituir elementos de nuestro código por otros cuya respuesta controlamos. Esto lo conseguimos reimplementamos la interfaz con lo que a nosotros nos interese.
- El hecho de ineyectar las dependencias nos permite redefinir comportamientos para poder hacer pruebas.
- Podemos simular código creando código auxiliar para poder simular los objetos en las pruebas, pero esto tiene limitaciones cuando la aplicación escala en tamaño y funcionalidades (mucho código extra para mantener).
- Frameworks para crear objetos simulados: NSubstitute, Moq, RhinoMocks, Foq, etc
- Cómo usar Moq: 1) crear un objeto tipo Mock<T>, 2) configurar el mock, 3) Reemplazar un objeto desde un mock.
- Lo más habitual es crear estos mock en el constructor de la clase de pruebas o en un accesorio, ya que así los vamos a poder utilizar en todas las pruebas aunque, si tienes la seguridad de que sólo vas a necesitarlo en una prueba en concreto, puede ir dentro de ella, en el Arrange.
Temas varios
- Tipos de pruebas
- Unitarias: Probar una única clase. Reciben un mock de las cosas que necesitan para poder funcionar.
- De integración: Verifican que la integración de las diferentes clases y servicios funcionan correctamente. En este tipo de pruebas es posible utilizar mocks para algunos niveles que todavía no se pueden probar, como por ejemplo un servicio de terceros.
- Funcionales: Probar el funcionamiento completo del sistema en base a los requisitos que tiene.
- TDD
- Es una forma de desarrollo ligada a las pruebas de código.
- Pasos
- Escribir las pruebas sobre un requisito concreto
- Hacer el código que haga pasar la prueba
- Por último, se hace una refactorización para dejar el código limpio
- TDD permite desarrollar funcionalidades de una manera muy sólida.
- Cobertura de código
- Es una métrica porcentual que nos da información sobre qué código se ha probado y cuál no.
- Los criterios (tipos) de cobertura del código más usados en un proyecto son: a) Cobertura de líneas (line coverage), b) Cobertura de ramas (branch coverage).
- Herramientas para medir la cobertura de código: Visual Studio Enterprise, extensión Resharper, Rider IDE, etc.
- Hay diferencias a la hora de generar un informe de cobertura de código en .NET Clásico y .NET
- Probar código Legacy
- Si se añade nueva funcionalidad, agregarle sus respectivo código de prueba
- Si se tiene que modificar compartamiento de un método viejo, evaluar si es viable crear un conjunto de pruebas para asegurar que no se rompe nada de ese código en concreto.
- Consejo: Al trabajar con código heredado se deben contener esas ansias de conseguir la perfección que nos caracteriza a los desarrolladores.
Integración Continua y testing
- Detectar que nuestro código funciona en otros servidores además de nuestro entorno local.
- La integración continua es la parte del desarrollo de software que se encarga de integrar cambios con mucha frecuencia para detectar fallos de manera rápida.
- Con la mayor frecuencia posible se compile el código desde 0 y se pasen todas las pruebas que haya en la solución.
- Problemas derivados del desarrollo en equipo:
- El código no compile
- Se haya roto alguna funcionalidad
- Con la Integración Continua podemos detectar errores relativos a dependencias.
- Gracias a la CI podemos tener siempre a mano una versión compilada con todos los cambios del equipo de desarrollo unidos.
- Herramientas para hacer CI:
- Online: Azure DevOps, GitHub Actions
- On-Premise: Jenkins
- La integración continua de nuestro proyecto se puede iniciar de diversas maneras: a través de un commit + push de Git, con un Webhook, programada a determinadas horas cada día...
- Proceso general de Integración Continua:
Links
Software Engineering Body of Knowledge (SWEBOK)
Software Engineering Design
Software design is an indispensable phase of the software engineering process for creating and evaluating software models that guide the construction effort for developing high-quality software systems on time and within budget.
Conceptually, design is the process of transforming functional and nonfunctional requirements into models that describe the technical solution before construction begins. To achieve this, the concept of software design, its activities, and tasks must be well understood so that a problem-solving framework for designing quality into software products can be established.
In today’s modern software systems, there are numerous design principles, processes, strategies, and other factors affecting how designers execute the software design phase. When equipped with the proper design foundation knowledge, an understanding of the designer’s roles and responsibilities can be acquired, allowing designers to become effective in designing large-scale software systems under a wide variety of challenging conditions.
Wednesday, January 11, 2023
The BDD Books - Discovery
Donde comprarlo
https://leanpub.com/bddbooks-discovery
