{"id":103,"date":"2021-06-11T01:07:38","date_gmt":"2021-06-11T06:07:38","guid":{"rendered":"https:\/\/lafilosofiadelsoftware.wordpress.com\/?p=103"},"modified":"2023-04-09T12:40:47","modified_gmt":"2023-04-09T17:40:47","slug":"como-hacer-buenas-pruebas-a-nuestro-codigo","status":"publish","type":"post","link":"https:\/\/lafilosofiadelsoftware.com\/index.php\/2021\/06\/11\/como-hacer-buenas-pruebas-a-nuestro-codigo\/","title":{"rendered":"\u00bfC\u00f3mo hacer buenas pruebas a nuestro c\u00f3digo?"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\" id=\"d16c\">Contexto actual de las pruebas a nuestro c\u00f3digo<\/h4>\n\n\n\n<p id=\"79a3\" style=\"font-size:15px\">Esta publicaci\u00f3n pretende dar una visi\u00f3n de c\u00f3mo se deben realizar buenas pruebas a nivel de c\u00f3digo (unit test) en nuestra aplicaci\u00f3n y est\u00e1 realizado bajo el lenguaje de programaci\u00f3n Kotlin (con librer\u00eda mockk) sin embargo lo que veamos puede ser f\u00e1cilmente extrapolado a otro lenguaje de programaci\u00f3n y librer\u00eda para hacer pruebas. No pretende dar una visi\u00f3n de hacer&nbsp;<a href=\"https:\/\/es.wikipedia.org\/wiki\/Desarrollo_guiado_por_pruebas\">TDD<\/a>&nbsp;sino el c\u00f3mo deben ser el resultado final de nuestras pruebas de c\u00f3digo.<\/p>\n\n\n\n<p id=\"017c\">Demos un vistazo a las siguiente imagen que nos muestra el antipatr\u00f3n de las pruebas:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/1e201-0a_dwjkxilii0br_f.png\" alt=\"\" width=\"281\" height=\"346\"\/><figcaption class=\"wp-element-caption\">Cono (Piramide) para mostrar antipatr\u00f3n de las pruebas en el software<\/figcaption><\/figure><\/div>\n\n\n<p id=\"765f\">Este gr\u00e1fico nos muestra el c\u00f3mo NO deben estar nuestras pruebas en c\u00f3digo. F\u00e1cil de tender \u00bfno?. El deber ser es invertir nuestro cono (o pir\u00e1mide) y que la base de todas nuestras pruebas sean unos buenos Unit Test. Sin embargo esto es bastante dif\u00edcil de cumplir en la gran mayor\u00eda de empresas y por eso tienen departamentos enteros de&nbsp;<a href=\"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/qa-quality-assurance-y-su-mundo\/\">QA<\/a>&nbsp;encargados de validar si el desarrollo que hicimos est\u00e1 \u2018ok\u2019.<\/p>\n\n\n\n<p id=\"fa72\">Estas pruebas manuales aparte de ser extremadamente costosas, lentas y depender de una persona para ejecutarlas es un modelo que no permite escalar f\u00e1cilmente, quienes han trabajado en proyectos grandes habr\u00e1n experimentado el c\u00f3mo tardan las dichosas pruebas de nuestros compa\u00f1eros QA y como sprint tras sprint se vuelve m\u00e1s y m\u00e1s dif\u00edcil probar, el m\u00e1s m\u00ednimo cambio toma d\u00edas en validarse.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"3ce6\">La falacia del Coverage<\/h4>\n\n\n\n<p id=\"81c9\">El&nbsp;<a href=\"https:\/\/es.wikipedia.org\/wiki\/Cobertura_de_c%C3%B3digo\">coverage<\/a>&nbsp;se volvi\u00f3 la medida principal para \u201cGarantizar\u201d una buena base de pruebas a nuestro sistema (Dios que hemos hecho), incluso algunas empresas\/proyectos un poco m\u00e1s maduros cuentan con pr\u00e1cticas como&nbsp;<a href=\"https:\/\/es.wikipedia.org\/wiki\/Integraci%C3%B3n_continua\">Continuous Integration<\/a>&nbsp;en el que si un&nbsp;<a href=\"https:\/\/www.atlassian.com\/es\/git\/tutorials\/making-a-pull-request\">Pull request<\/a>&nbsp;no cuenta con un buen porcentaje de coverage (lo com\u00fan es ver 85%) no funciona.<\/p>\n\n\n\n<p id=\"037e\">No me malinterpreten, no estoy diciendo que el coverage sea malo y mucho menos que tener un CI lo sea, lo que trato de decir es que confiar \u00fanicamente en el coverage nos puede jugar una mala pasada, o si no preg\u00fantese a s\u00ed mismos realmente \u00bfconf\u00edo en las pruebas unitarias? Algunos podr\u00e1n decir que S\u00ed, en caso de que lo hagan pregunten \u00bfPasamos a producci\u00f3n sin un proceso de QA? y ver\u00e1n como el miedo y ese aire fr\u00edo de incertidumbre se apodera de su rostro. Esto sucede porque nuestras pruebas unitarias realmente no prueban nada, solo pasan por las l\u00edneas de c\u00f3digo marcandolas como cubiertas haciendo el papel de un visitante que no hace verificaciones o aserciones de l\u00f3gica de negocio valiosa.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"5a5a\">\u00bfC\u00f3mo identificar malas pruebas unitarias?<\/h4>\n\n\n\n<p id=\"9548\">Esto se puede responder con bastante tecnicismos o incluso con librer\u00edas que pueden ayudarte (<a href=\"https:\/\/www.baeldung.com\/java-mutation-testing-with-pitest\" title=\"mutation test\">mutation test<\/a>) a detectar esto, pero realmente por donde debemos empezar es ejecutando estas acciones:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Borremos c\u00f3digo y corramos nuevamente las pruebas.<\/li>\n\n\n\n<li>Invirtamos este condicional IF (o eliminarlo) y corramos nuevamente las pruebas.<\/li>\n\n\n\n<li>Quitemos la invocaci\u00f3n de X componente externo y corramos nuevamente las pruebas.<\/li>\n<\/ul>\n\n\n\n<p id=\"5b26\">Si ejecutando las pruebas con alguna de estas 3 acciones anteriores tus pruebas no se vieron afectadas, \u00a1Malas noticias! cuentas con malas pruebas unitarias.<\/p>\n\n\n\n<p id=\"193b\">Estas pruebas es el primer nivel para garantizar que nuestro c\u00f3digo realmente est\u00e9 realmente probado, veamos el segundo nivel:<\/p>\n\n\n\n<p id=\"c16a\">Nuestras pruebas unitarias deben de cumplir un prop\u00f3sito, un para que existe, por decirlo de otra manera nuestras pruebas necesitan una raz\u00f3n de vida. Si no tienen una raz\u00f3n de ser elim\u00ednala cuantos antes esta es una mala prueba y te vas a llenar de falsos positivos.<\/p>\n\n\n\n<p id=\"2a8f\">Para lograr lo anterior nuestras pruebas deben estar orientada a garantizar un caso de negocio (uso) y velar porque se est\u00e9 cumpliendo, puede sonar un poco complicado de cumplir cuando realmente no lo es, el secreto est\u00e1 en hacer un buen&nbsp;<a href=\"https:\/\/martinfowler.com\/bliki\/GivenWhenThen.html\">given-when-then<\/a>. No hay que ser el developer mas estricto para lograr esto, solo es cuesti\u00f3n que la prueba tenga su prop\u00f3sito veamos esto en acci\u00f3n, \u00a1vamos al c\u00f3digo!<\/p>\n\n\n\n<p id=\"c02f\"><strong>Caso Hipot\u00e9tico:<\/strong><\/p>\n\n\n\n<p id=\"4abf\">Nuestro m\u00e9todo de venta de libros debe verificar que la cantidad de libros no exceda 5, si lo excede debe impedir la venta y en caso de que sea 5 debe adicionar como regalo una membres\u00eda como lector premium a nuestro cliente.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/ff888-0lotsijided6xs-2n.png\" alt=\"\" width=\"538\" height=\"178\"\/><\/figure>\n\n\n\n<p id=\"ad3c\">Hagamos las pruebas de manera iterativa e incremental de c\u00f3mo deben ser las pruebas.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Esta \u201cprueba\u201d ejecuta el llamado del servicio<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/651cc-0b1adppwm_wltwpoj.png\" alt=\"\" width=\"527\" height=\"364\"\/><figcaption class=\"wp-element-caption\">Ejemplo de muchas \u2018pruebas\u2019 encontradas en la industria<\/figcaption><\/figure>\n\n\n\n<p id=\"d259\">vean el resultado del coverage:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/8f19c-0uoqyhx73glkvnpib.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"7207\">Tenemos 77% de coverage con una prueba que no hace absolutamente NADA<\/p>\n\n\n\n<p id=\"df57\">2. Agregamos a nuestra \u201cprueba\u201d 5 libros<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/6b54d-0letfbqgf5a_d2nq_.png\" alt=\"\" width=\"484\" height=\"240\"\/><figcaption class=\"wp-element-caption\">Solo agregando 5 libros a la \u201cprueba\u201c mejora el coverage<\/figcaption><\/figure>\n\n\n\n<p id=\"d268\">Miremos el coverage:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/cb192-0by0umudnnxzdqske.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"5d16\">Con este coverage ya pasar\u00e1 la mayor\u00eda de los CI los cuales tienen como m\u00ednimo 85% de coverage por cumplir.<br><em>\u00bfEs m\u00e1s claro ahora lo peligroso que puede ser confiar en \u00fanicamente en el coverage?<\/em><\/p>\n\n\n\n<p id=\"fb4f\"><strong>3.<\/strong>&nbsp;Ahora apliquemos unos&nbsp;<a href=\"https:\/\/www.telerik.com\/products\/mocking\/unit-testing.aspx\">Mock<\/a>&nbsp;sobre los llamados a \u2018servicios\u2019 externos que su funcionamiento interno no hace parte de las pruebas unitarias.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/3f8f4-0eblzw4dz9haxrrmp.png\" alt=\"\" width=\"606\" height=\"410\"\/><figcaption class=\"wp-element-caption\">Se cambia el nombre de la prueba para que tenga una finalidad o caso para verificar<\/figcaption><\/figure>\n\n\n\n<p id=\"7166\">a. Separamos en un m\u00e9todo independiente la carga de data que necesita nuestra prueba (Algo muy usado es enviarlo a una Clase encargada de generar data para los test)<\/p>\n\n\n\n<p id=\"178b\">b. Ingresamos un&nbsp;<a href=\"https:\/\/notwoods.github.io\/mockk-guidebook\/docs\/mocking\/stubbing\/\">every<\/a>&nbsp;para simular las respuestas de nuestros \u2018servicios\u2019 externos<\/p>\n\n\n\n<p id=\"5a94\">c. Agregamos un&nbsp;<a href=\"https:\/\/notwoods.github.io\/mockk-guidebook\/docs\/mocking\/verify\/\">verify<\/a>&nbsp;para corroborar que se invoc\u00f3 el registro de una nueva membres\u00eda y en caso de que alguien modifique nuestro m\u00e9todo de \u2018sellBook\u2019 y elimine el registro de membres\u00eda cuando se tenga 5 registros nuestra prueba unitaria fallar\u00e1 y MAGIA tenemos una prueba unitaria que realmente valida un comportamiento de negocio y en caso de que afecte el m\u00e9todo nuestra prueba lo notificar\u00e1<\/p>\n\n\n\n<p id=\"1852\">d. Como tal nuestro coverage se mantuvo con 86% con el cambio que realizamos, pero este 86% realmente nos da m\u00e1s confiabilidad que las anteriores iteraciones.<\/p>\n\n\n\n<p id=\"7641\"><strong>4<\/strong>. Ahora solo nos falta verificar el fallo cuando exceda la cantidad de libros<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/fbf69-0tqkv96a1rbrdj2fv.png\" alt=\"\" width=\"574\" height=\"531\"\/><figcaption class=\"wp-element-caption\">Clase de pruebas que valida escenarios de nuestra l\u00f3gica de negocio<\/figcaption><\/figure>\n\n\n\n<p id=\"95f9\">Con esta prueba garantizamos el comportamiento que debe suceder en nuestra aplicaci\u00f3n si una venta viene con m\u00e1s de 5 libros y llegamos a un coverage del 100%<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/lafilosofiadelsoftware.files.wordpress.com\/2021\/06\/3c78c-0ysaizy4ohpokovlp.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"5702\">Tips: Para ayudar a nuestras pruebas unitarias validen comportamientos debemos apoyarnos principalmente en los&nbsp;<em>verify, assertEquals.<\/em><\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"a5f7\">Unas buenas pruebas unitarias te har\u00e1n ahorrar horas de desarrollo<\/h4>\n\n\n\n<p id=\"b792\">Para nadie que trabaje en esta industria es un secreto que el mayor tiempo que se dedica al proceso de ingenier\u00eda de software es el de mantenimiento, en el que una vez se finaliza al menos una primera versi\u00f3n del software salen y salen nuevos requisitos o ajustes por hacer a nuestro sistema tendiendo hacia el infinito y solo deteni\u00e9ndose en el momento que nuestra aplicaci\u00f3n es reemplazada por una mas nueva. Por lo tanto no s\u00f3lo debemos preocuparnos por terminar nuestro desarrollo sino tambi\u00e9n que sea f\u00e1cilmente mantenible y esto lo podemos lograr con unas buenas pruebas unitarias. Si han tenido la oportunidad de trabajar con c\u00f3digo ya existente habr\u00e1n sentido la angustia que se siente que nuestro nuevo desarrollo da\u00f1e algo que ya previamente funcionaba bien. Esta angustia puede ser f\u00e1cilmente disminuida si al momento que el developer nuevo da\u00f1a algo inmediatamente falla una prueba, con esto las horas y horas de debug en b\u00fasqueda de ese error que se nos present\u00f3 se ver\u00e1n eliminadas.<\/p>\n\n\n\n<p id=\"3692\">Tomen lo anterior como una invitaci\u00f3n a dedicarnos un buen tiempo ha hacer buenas pruebas unitarias y ahorrarnos dolor de cabeza m\u00e1s adelante o a futuros developers de nuestra aplicaci\u00f3n.<\/p>\n\n\n\n<p id=\"8a0a\">Por \u00faltimo les dejo estas dos frases que siempre comparto con los equipos que trabajo:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Haz tu c\u00f3digo pensando que la persona que lo mantendr\u00e1 es un asesino psic\u00f3pata y sabe donde vives.<\/li>\n\n\n\n<li>Si algo es dif\u00edcil de probar es porque est\u00e1 mal desarrollado (Frase compartida por un gran colega&nbsp;<a href=\"https:\/\/www.linkedin.com\/in\/rcabezas1\/\">Edwin Romero<\/a>)<\/li>\n<\/ul>\n\n\n\n<p><a href=\"https:\/\/daniel-saavedra-fon.medium.com\/?source=post_page-----f482b3e8f464--------------------------------\"><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aprende a escribir buenas pruebas unitarias en tu c\u00f3digo<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3],"tags":[11,14,19,21],"class_list":["post-103","post","type-post","status-publish","format-standard","hentry","category-software-engineer","tag-ingeniera-de-software","tag-qa","tag-software-engineer","tag-unit-test"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/posts\/103"}],"collection":[{"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/comments?post=103"}],"version-history":[{"count":2,"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/posts\/103\/revisions"}],"predecessor-version":[{"id":249,"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/posts\/103\/revisions\/249"}],"wp:attachment":[{"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/media?parent=103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/categories?post=103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lafilosofiadelsoftware.com\/index.php\/wp-json\/wp\/v2\/tags?post=103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}