scieee AI-readable full text Open interactive document viewer

Generación automática de casos de prueba mediante modelos de lenguaje (LLM)

Barahona Cánovas, Ismael; Contreras Gordo, Gonzalo

Abstract

Este trabajo de fin de grado tiene por objetivo la generación de casos de prueba de forma automática, empleando modelos de lenguaje. Los casos de prueba deben respetar el criterio de cobertura métrica MC/DC (Condición Modificada/Cobertura de Decisión), una subclase de cobertura de código para bloques condicionales if-then-else. Esta estructura extiende la cobertura de decisión y condición, exigiendo que cada condición debe afectar independientemente en la decisión, es decir que enseña cómo todas las entradas dadas afectan de forma independiente a la salida de una expresión lógica. Este TFG extiende trabajos anteriores. Concretamente, se ha actualizado y empaquetado un motor heurístico preexistente para la generación de casos de prueba conforme al criterio MC/DC en una biblioteca de Python. Posteriormente se ha añadido a esa biblioteca un segundo generador de casos de prueba para el criterio MC/DC basado en un modelo de lenguaje. Por último, se ha integrado la biblioteca de generación de casos de prueba en un plugin para el entorno de desarrollo Visual Studio Code para facilitar su uso por parte de los programadores. La herramienta permite generar casos de prueba para maximizar la cobertura MC/DC de un código en Python. Gracias a su modularidad, esta herramienta se podrá extender en el futuro para soportar otros lenguajes de programación y criterios de cobertura.

Full text

GENERACIÓN AUTOMÁTICA DE CASOS DE PRUEBA MEDIANTE MODELOS DE LENGUAJE (LLM) AUTOMATIC TEST CASE GENERATION USING LARGE LANGUAGE MODELS (LLM) TRABAJO FIN DE GRADO CURSO 2023-2024 AUTORES ISMAEL BARAHONA CÁNOVAS GONZALO CONTRERAS GORDO DIRECTOR JOSÉ IGNACIO REQUENO JARABO MARÍA ELENA GÓMEZ MARTÍNEZ GRADO EN INGENIERÍA INFORMÁTICA FACULTAD DE INFORMÁTICA UNIVERSIDAD COMPLUTENSE DE MADRID GENERACIÓN AUTOMÁTICA DE CASOS DE PRUEBA MEDIANTE MODELOS DE LENGUAJE (LLM) AUTOMATIC TEST CASE GENERATION USING LARGE LANGUAGE MODELS (LLM) TRABAJO DE FIN DE GRADO EN INGENIERÍA INFORMÁTICA AUTORES ISMAEL BARAHONA CÁNOVAS GONZALO CONTRERAS GORDO DIRECTOR JOSÉ IGNACIO REQUENO JARABO MARÍA ELENA GÓMEZ MARTÍNEZ CONVOCATORIA: JUNIO 2024 GRADO EN INGENIERÍA INFORMÁTICA FACULTAD DE INFORMÁTICA UNIVERSIDAD COMPLUTENSE DE MADRID 27 DE MAYO DE 2024 Dedicatoria Ismael Barahona Cánovas A mis padres, José María y Matilde por darme todo lo necesario como persona y como hijo para lograr todas mis metas y objetivos, así como a mi hermano Daniel sin el cual nada sería igual. A mis amigos y seres queridos que estuvieron a mi lado, brindándome ánimo y comprensión en todo momento. Su apoyo fue fundamental para superar obstáculos y mantenerme enfocado. Además de ayudar a evadir algunos de los numerosos obstáculos que tiene la vida universitaria. Destacando a las amistades que he conseguido en la facultad como Gonzalo Contreras, Pablo Lozano y Pablo Pezo que son los pilares que me han soportado todos los días desde primer año. No se me olvida destacar la frase que me han repetido en mi familia: la carrera universitaria es como su nombre indica una carrera, lo importante es acabarla. Gonzalo Contreras Gordo Dedico este trabajo a mis padres Leandro y Ana Rosa, y a mi hermana Irene, que me han apoyado, aconsejado y motivado toda mi vida para perseguir mis objetivos y no rendirme por conseguirlos, así como por el cariño constante que me demuestran día a día. A mis amigos de siempre, Laura, Juan y David que me acompañan en todo momento, sea bueno o malo, y que siempre me animan a dar lo mejor de mí. Y a todos mis compañeros y amigos que he hecho a lo largo de mi estancia en la facultad, que han sido unos hermanos de armas excelentes para enfrentarse al reto que supone la universidad. Destacando a Ismael, Pablo L., Pablo P. y María que ahora forman una parte importante de mi vida, algo por lo que estoy muy agradecido. Agradecimientos Agradecer a María Elena Gómez Martínez y José Ignacio Requeno Jarabo pues han sido los mejores tutores que hemos podido tener, proporcionándonos ayuda en todo momento, así como agradecer la ayuda y mejora proporcionada por Lukas Sebastian Hofmann en el desarrollo de este proyecto. Resumen GENERACIÓN AUTOMÁTICA DE CASOS DE PRUEBA MEDIANTE MODELOS DE LENGUAJE (LLM) Este trabajo de fin de grado tiene por objetivo la generación de casos de prueba de forma automática, empleando modelos de lenguaje. Los casos de prueba deben respetar el criterio de cobertura métrica MC/DC (Condición Modificada/Cobertura de Decisión), una subclase de cobertura de código para bloques condicionales if-thenelse. Esta estructura extiende la cobertura de decisión y condición, exigiendo que cada condición debe afectar independientemente en la decisión, es decir que enseña cómo todas las entradas dadas afectan de forma independiente a la salida de una expresión lógica. Este TFG extiende trabajos anteriores. Concretamente, se ha actualizado y empaquetado un motor heurístico preexistente para la generación de casos de prueba conforme al criterio MC/DC en una biblioteca de Python. Posteriormente se ha añadido a esa biblioteca un segundo generador de casos de prueba para el criterio MC/DC basado en un modelo de lenguaje. Por último, se ha integrado la biblioteca de generación de casos de prueba en un plugin para el entorno de desarrollo Visual Studio Code para facilitar su uso por parte de los programadores. La herramienta permite generar casos de prueba para maximizar la cobertura MC/DC de un código en Python. Gracias a su modularidad, esta herramienta se podrá extender en el futuro para soportar otros lenguajes de programación y criterios de cobertura. Palabras clave MC/DC, casos de prueba, automatización, LLM, expresión booleana, cobertura de decisión, cobertura de condición, Visual Studio Code, extensión, inteligencia artificial ÍNDICE DE TABLAS Tabla 1: Tabla de verdad ...........................................................................................14 Tabla 2: Ejemplo MC/DC ............................................................................................14 Tabla 3: Comparación de plataformas ....................................................................21 Tabla 4: Comparación de salidas de los generadores ...........................................45 1 1 Capítulo 1 - Introducción 1.1 Motivación Actualmente, en el mundo del desarrollo de software, existe una gran diversidad de programas cada vez más complejos con un impacto crítico en la sociedad en caso de fallo (p.ej., piense en el sector bancario, las comunicaciones o el transporte). Por tanto, estos sistemas requieren de unos mínimos de calidad y fiabilidad para garantizar su correcto funcionamiento. La necesidad de desarrollar software que cumpla estos estándares ha provocado que el testing de software [1] [2] adquiera una importancia vital en el proceso de desarrollo de todo programa de software. El objetivo del testing es encontrar y corregir errores, garantizando una mayor calidad del software desarrollado, así como la reducción del coste del mantenimiento de este asegurando así la satisfacción de los usuarios. Para conseguir este objetivo, la principal herramienta del probador de software son los tests, que se componen de una tupla de valores de entrada, así como el valor esperado de salida. Esta tupla de (valores de entrada, salida esperada) es denominada caso de prueba, y es la parte más importante de toda prueba, pues tienen la función de poner a prueba el código del programa en escenarios específicos para poder evaluar su comportamiento en toda clase de situaciones, desde las más comunes hasta las más complejas. La efectividad de estos casos de prueba reside en su capacidad para encontrar fallos y así asegurar el correcto funcionamiento del programa en cualquier situación. Estos casos de prueba se diseñan siguiendo ciertos criterios de cobertura, es decir una serie de métricas y enfoques para medir las partes que han sido ejecutadas durante las pruebas. Es por ello por lo que estos criterios deben ser efectivos para poder garantizar una cobertura adecuada de todas las partes del software y así poder identificar de forma efectiva fallos en el código. 2 El esfuerzo y dificultad en la creación manual de casos de prueba han incrementado junto a la complejidad actual de los programas, por lo que se ha convertido en una tarea ardua que es más propensa a errores. Esto provoca que realizar un testing exhaustivo tenga un coste económico y temporal elevado por lo que, siendo conscientes de este problema, se plantea una solución, la generación automática de casos de prueba, que pretende optimizar la importante tarea que es el testing de software, agilizando el proceso de la creación de los casos de prueba, así como aumentar su calidad. En este TFG exploramos la generación automática de los casos de prueba mediante el uso de Modelos de Lenguaje (LLM, Large Language Models) [3] bajo el criterio de cobertura MC/DC [4], un tipo especial de cobertura de salto (branch coverage en inglés). Este criterio de cobertura es utilizado en estándares industriales (sector aeroespacial, estándar DO-178C [5], y automovilístico, estándar ISO 26262 [6]) para garantizar la fiabilidad y seguridad de los productos software implementados en el sector aeroespacial y automovilístico respectivamente. Estos estándares abordan desde los procesos de desarrollo de software hasta la gestión de la calidad y la seguridad de este. Los fallos se clasifican según su severidad permitiendo así una priorización de estos en los tests para alcanzar la mayor fiabilidad y seguridad posible. A la hora de ejecutar los tests, el uso del criterio de cobertura MC/DC garantiza una mayor sensibilidad a la cobertura de ramas. Además de ello, los conjuntos de tests que satisfacen el criterio MC/DC son mucho más reducidos que aquellos que cumplen con el criterio de cobertura de ramas. Es por ello por lo que el tiempo que lleva ejecutar las pruebas se reduce drásticamente a la par que aumenta su efectividad. Sin embargo, conseguir un conjunto mínimo (óptimo) de tests que satisfaga el criterio MC/DC es costoso y difícil, por lo que normalmente se logran aproximaciones. Para solventar esta limitación, se ha propuesto una heurística que aproxime la generación de tests con el criterio MC/DC mediante la ayuda de plataformas LLM. 3 Con esto se ofrece una forma sencilla de generación de casos de prueba efectivos con el objetivo de optimizar el proceso de testing de software, aumentar la calidad del software y hacer del testeo de este una tarea menos costosa en términos temporales y económicos. 1.2 Objetivos El principal objetivo de este Trabajo de Fin de Grado, es la generación automática de casos de prueba mediante modelos de lenguaje. Para lograr el correcto desenlace de este objetivo se debe cumplir con una serie de objetivos específicos: ● Adquisición de conocimientos y diferentes recursos de información sobre el criterio de cobertura MC/DC, para poder entender hasta qué punto nuestro desarrollo automático ha sido positivo o negativo. ● Actualización y mejora de una herramienta heurística preexistente para la generación de casos de prueba que satisfagan los criterios MC/DC. ● Implementación de una extensión/módulo en VS Code para la generación automática de casos de prueba a través de la conexión con un LLM. ● Implementación de un plugin para un entorno de desarrollo (IDE) que facilite el uso de la herramienta de generación de casos de prueba por usuarios no expertos y encapsule los dos motores de generación de casos de prueba previamente mencionados (generadores mediante de casos de prueba mediante un LLM y generador de casos de prueba mediante la herramienta heurística preexistente). En particular, se ha escogido el editor de código VS Code como IDE donde hospedar el plugin. ● Comparación de salidas de ambos generadores de casos de prueba con relación al criterio MC/DC para ver la calidad de nuestra generación automática mediante LLM. Con este conjunto de objetivos llevados a cabo de forma correcta se podrá llegar a asegurar que el objetivo principal ha sido cumplido. 4 1.3 Plan de trabajo Para el desarrollo del trabajo se empleará una metodología híbrida denominada Scrumban, la cual combina elementos de la metodología Scrum enfocándonos en la entrega de avances en ciclos cortos por eso usaremos la página Jira Software [7] (Ilustración 1), en la cual se creará una estructura dividida en sprints y la metodología Kanban dado que en dicha página podemos observar un tablero con el estado de las tareas y el propio flujo del desarrollo. Desarrollando el apartado de la estructura de trabajo estará dividida en distintos sprints, los cuales desde el inicio se establecerán en una duración básica de una semana, siendo este periodo adaptable por la cantidad de tareas/ trabajo a realizar. Tras este tiempo se realizarán reuniones con los tutores en estas reuniones se mostrará el avance realizado y se darán por finalizados los sprints y se iniciará el siguiente. La cantidad de trabajo en cada sprint se representará a través de tareas agrupadas por clases (Ilustración 2 y 3), estas podrán ser creadas por los tutores o por los estudiantes. Estas tareas se podrán ir moviendo entre cinco estados: ● Por hacer ● En progreso ● En revisión ● En pausa ● Hecho Estos permiten indicar si se pueden dar por cerradas al terminar el sprint o deben seguir abiertas para el siguiente. 1.3.1 Fases del proyecto Para el desarrollo de este trabajo, se ha seguido una serie de fases que han permitido proceder de manera ordenada, asegurando que no se saltaran conceptos o acciones clave. 1.3.1.1 Primera fase: Investigación y toma de conocimientos 5 Se comienza el proyecto buscando distintas fuentes de información para tener claros los conceptos básicos y obtener información sobre el término novedoso para nosotros que aparece en este trabajo, como es el criterio de cobertura MC/DC. También se ha tenido que hacer un repaso del lenguaje empleado en el código de la herramienta heurística preexistente, Python [8]. Este lenguaje se utiliza para la generación de casos de prueba a través del plugin heurístico, por lo que se debe desarrollar conocimiento para así poder interactuar con el código proporcionado. A su vez, el plugin en Visual Studio recibirá código fuente (condicionales if-thenelse de Python) y generará casos de prueba que satisfagan el criterio MC/DC. Por último, se estudian otros lenguajes de programación y tecnologías necesarios para el desarrollo del plugin en VS y las opciones de conexión con los modelos de lenguaje. Un ejemplo de estos lenguajes de programación es Typescript [9] [10] con el cual realizamos la extensión que tendrá la posibilidad de emplear los dos métodos de generación. Con esto las primeras semanas serán ocupadas por estas primeras partes de búsqueda de información. 1.3.1.2 Segunda fase: Preparación del entorno de trabajo de la herramienta preexistente Para la fase de instalación y adaptación al entorno de programación, se comienza instalando e intentando ejecutar un ejemplo básico del generador con la heurística preexistente. Para esto se emplea WSL [11], siendo esta una herramienta o característica de Windows que permite a los usuarios ejecutar un entorno de Linux dentro de Windows y así poder ejecutar de forma más cómoda el código. 1.3.1.3 Tercera fase: Empaquetado y actualización de la biblioteca previa para la generación de casos de prueba Una vez con todo disponible se pone en marcha el empaquetado y actualización del código de una herramienta de generación de casos de prueba que se proporciona. La biblioteca genera casos de prueba mediante heurísticas convencionales, ajenas a las técnicas basadas en LLM. Junto con los motores basados en LLM, formará parte del 6 plugin final realizado en VS Code para la generación automática de casos de prueba. La biblioteca servirá como punto de comparación de la calidad de los casos de prueba generados por el LLM, para un mismo problema de cobertura. Empieza la redacción de esta memoria para no tener ningún problema a futuro, comenzando el capítulo 1 y los apartados previos como resumen, palabras clave y motivación. En el código comenzamos con la elaboración de una correcta estructura dividiendo los diferentes archivos en librerías. 1.3.1.4 Cuarta fase: Implementación de extensión empleando la conexión a un LLM Se continua con la elaboración de una extensión, con la cual se recogen las respuestas generadas por un LLM, a través de este desarrollo se busca pedir a la inteligencia artificial que genere casos de prueba para una expresión dada. Esta implementación estuvo planteada en dos entornos uno era Jupyter Notebooks y el otro VS Code, tras varias semanas de pruebas se decidió implementar a través de VS Code. La extensión comenzó siendo dividida en dos partes una dirigida hacia la generación mediante el uso de librerías y otra mediante el uso de la conexión con un LLM. La implementación de la parte por librería fue complicada, pero a partir de aplicarle cierto periodo de tiempo se logró avanzar de manera positiva. Por su parte la implementación mediante LLM llevo un largo tiempo puesto que era un entorno nuevo y poco explorado, pero se pudo lograr en el tiempo estipulado para tener las dos partes listas. Tras tener las primeras versiones de estas extensiones se unieron en una sola, consiguiendo así poder ejecutar a través de un menú contextual. Creando con esto el capítulo 3 de esta memoria. 1.3.1.5 Quinta fase: Comparación de salidas de los generadores Con la extensión implementada de manera correcta se comienza a hacer comparaciones de salidas entre los dos métodos de generación. Observando las salidas 7 generadas por el LLM nos damos cuenta de que puede que se necesite comprobar de manera precisa si cumplen los criterios de MC/DC. 1.3.1.6 Sexta fase: Redacción de la memoria y mejora de comprensión de la extensión de LLM Esta fase se centra en redactar varios de los apartados de la memoria presentes en el capítulo 1 y 2, así como en desarrollar una comparación detallada entre las salidas de los generadores 1.3.1.7 Séptima fase: Avance de la memoria y mejora de elementos del código En esta fase se continúa desarrollando apartados de la memoria, así como realizando las correcciones necesarias. Aplicando mejoras en el repositorio de GitHub [12] para facilitar su comprensión. Además, se crea un archivo READ.ME acorde con el código de la extensión, abordando todos los elementos importantes, como dependencias, método de ejecución, contexto y ejemplos de ejecución. 1.3.1.8 Fase Final: Función de comprobación y finalización de la memoria En esta fase se ha implementado y perfeccionado la función de comprobación con la cual se verifica la correcta generación de los casos de prueba mediante el LLM y se completa la redacción de la memoria con los últimos apartados siendo estos el capítulo 4 y el capítulo 5, además de completar los elementos restantes como citas e índices. 14 ● Para la expresión rellenamos con la solución que da con el valor indicado a cada variable. ● Para la columna MC/DC parejas, vamos a fijar las variables en un caso menos una, la cual vamos a modificar a su valor opuesto para ver si así se altera la salida de la expresión. En caso de variar lo dejamos indicado, así conseguimos las parejas que indican que dos filas son las que se han comparado, en este caso A tiene 3 parejas. Tabla 1: Tabla de verdad Nr A B C A or (B and C) MC/DC parejas 1 0 0 0 0 2 0 0 1 0 A (2,6) 3 0 1 0 0 A (3,7) 4 0 1 1 0 A (4,8) 5 1 0 0 0 B (5,7) 6 1 0 1 1 C (5,6) 7 1 1 0 1 8 1 1 1 1 Como requerimos de n+1 MC/DC parejas siendo n el número de variables presentes en la expresión. En este ejemplo n=3, por lo tanto, necesitamos 4 parejas para ello tomaremos solo una pareja de A y su expresión modificando el valor de A al inverso para formar nuestro mínimo conjunto (Tabla 2). Tabla 2: Ejemplo MC/DC Nr A B C A or (B and C) MC/DC pairs 0 1 0 0 1 1 0 1 A (3,7) 15 1 0 0 0 B (5,7) 1 0 1 1 C (5,6) Por lo tanto, nuestro resultado sería el formado por estas entradas: ● A, not B, C ● not A, not B, C ● not A, B, C ● not A, B, not C Esta demostración también puede ser representada para expresiones de valor entero, usando el caso de la solución de la expresión A or (B and C) se puede generalizar para A>10 or (B <10 and C>9). ● Large Language Models (LLMs): son modelos de inteligencia artificial entrenados para entender y generar lenguaje natural. Estos modelos son capaces de aprender patrones complejos en datos de texto y realizar tareas como traducción, generación de texto coherente, imágenes, etc. Estos modelos pueden además ser entrenados para tareas más específicas lo que los vuelve muy útiles para tareas de generación de todo tipo de contenido en gran cantidad de aplicaciones. Los LLMs más populares están disponibles como servicios web y se pueden acceder a ellos mediante llamadas a su API. Es decir, permiten realizar consultas bajo el paradigma de “cliente-servidor”, siendo esta la forma que hemos escogido para interactuar con los LLMs de este trabajo. Existe otra opción para el uso de LLMs que consiste en descargar y ejecutar los modelos localmente utilizando contenedores (Docker) [15]. Esta alternativa ofrece la ventaja de poder trabajar sin depender de conexiones a internet y mantener los datos y modelos en un entorno controlado. ● Motor heurístico PyMCDC: emplea una heurística que proporciona entre n+1 y 2n casos de prueba que satisfacen el criterio MC/DC (con n el número de variables booleanas de la decisión). Codifica las decisiones (expresiones booleanas) como 16 un "árbol de decisión binario". Según el tipo de recorrido del árbol (LongestMayMerge, Short, etc), proporciona un conjunto de testcases u otros [16]. 2.2. Estado del arte En esta sección se revisan algunas herramientas de generación de casos de prueba que siguen el criterio de cobertura MC/DC, así como de las heurísticas o técnicas que utilizan para generar los casos en la actualidad. ● Algoritmos de búsqueda basados en métodos voraces y metaheurísticas: Se extraen caminos del grafo de flujo del programa para después generar los datos de test que cumplan con las condiciones necesarias usando un solver SMT (Teorías de satisfactibilidad módulo) [17] y, posteriormente, se reduce el conjunto de pruebas con un método voraz para conseguir así la cobertura MC/DC. Sin embargo, se pierde mucho esfuerzo computacional ya que un número elevado de caminos escogidos llegan a ser inviables. ● SAT Solver: Se hace uso de un SAT solver [18] para construir conjuntos de prueba mínimos. Esto se realiza en una única consulta en la que se codifica el criterio MC/DC, y el solver produce una asignación adecuada de los valores de entrada de los casos de prueba si es que existe alguna. Sin embargo, en ocasiones puede llevar a errores timeout debido a la exhaustividad de las consultas SAT. ● Grafos n-cubo y código Gray: Toma una expresión booleana como entrada, construye el grafo n-cubo [19] y deduce los casos de prueba de los vértices del grafo. La selección de casos se basa en el peso de cada caso de prueba. Su mayor inconveniente es que el conjunto de pruebas no es mínimo. ● Análisis sintáctico y semántico de los requerimientos funcionales a través de GIC: Se propone una plataforma que primero analiza los requerimientos funcionales, a partir de ellos, genera los casos de prueba. Esta herramienta [20] consta de un 17 analizador de archivos, con el que estandariza el formato de escritura de los requerimientos a través de una gramática independiente del contexto y de un módulo generador que trabaja junto al analizador y que sigue el criterio MC/DC. Este recibe el árbol sintáctico generado por el analizador y a partir de ahí construye los conjuntos de pruebas. 2.3. Entorno de conexiones con LLM Para la generación de casos de manera automática destaca el modelo gpt-3.5turbo, dado que se trata de un modelo de texto capaz de entender y generar lenguaje natural. Las siguientes plataformas y herramientas proporcionan o integran esa versión de la inteligencia artificial: ● OpenAI API ● Azure OpenAI Services ● Hugging Face ● Google Cloud Natural Language API Todas estas plataformas están accesibles a través de servicios web, mediante interfaces de programación de aplicaciones (API). Cuando los desarrolladores desean utilizar las capacidades de estas plataformas en aplicaciones, deben emplear solicitudes HTTP a través de la red, utilizando las API proporcionadas. Como paso previo al uso de cualquiera de estos motores LLM, es necesario configurar una clave de acceso (API key) (Ilustración 4). 18 Ilustración 4: Acción de una API Las API key son códigos únicos y privados empleados para autenticar y autorizar el acceso a una API, actuando como identificador para desarrolladores. Para obtener estas llaves debes acceder a los sitios web de cada aplicación, dado que se emplean en cada solicitud que hacemos hacia la API. 2.3.1. OpenAI API La empresa OpenAI [21] [22] ha sido conocida por sus avances significativos en IA, así como por su compromiso con la transparencia y la seguridad en el desarrollo de tecnologías de inteligencia artificial. Es la entidad por excelencia debido a sus avances en los modelos de lenguaje, como el empleado en este TFG el GPT (Generative Pretrained Transformer), este permite a los desarrolladores generar texto, realizar traducciones, responder preguntas. Este recurso es muy común por lo tanto existen varios entornos con información precisa de cómo actuar de cara a la conexión con la API, como la propia página del producto la cual tiene todo el lujo de detalles, pero a pesar de esto suelen surgir diversos errores. 19 ● Clave de API incorrecta, cuando la clave de acceso que empleas no está correctamente configurada o no tiene los permisos necesarios para acceder al servicio en línea. ● La URL incorrecta, al indicar el endpoint de tu conexión al servicio en línea este no es el correcto, en este caso se debe asegurar que endpoint son los correctos para cada modelo que deseas utilizar. Dos ejemplos de endpoint son los empleados por: ○ Los nuevos modelos creados a partir del 2023: gpt-4, gpt-4-turbo-preview, gpt-3.5-turbo, los cuales emplean como endpoint https://api.openai.com/v1/chat/completions ○ Los modelos actualizados de legado (2023): gpt-3.5-turbo-instruct, babbage-002, davinci-002, los cuales emplean como endpoint https://api.openai.com/v1/completions ● Problemas de autorización, al intentar acceder a servicios los cuales no tienes permisos aplicados desde tu cuenta. ● Límites de solicitud excedidos, indica que se ha superado el número permitido de solicitudes dentro de un período de tiempo específico. Este límite puede ser impuesto por el proveedor del servicio al que se está intentando acceder. 2.3.2. Azure OpenAI Services Azure [23] es una plataforma en la nube, a través de la cual podemos trabajar con la inteligencia artificial, proporcionada por Microsoft ofrece una amplia gama de servicios de computación, almacenamiento, bases de datos, análisis, redes, inteligencia artificial y más. Estos servicios se pueden utilizar para construir, implementar y administrar aplicaciones y servicios de manera eficiente y escalable, sin necesidad de invertir en infraestructura física. Para poder emplear esta infraestructura debes tener una suscripción, en este caso, hemos empleado la cuenta de correo de la Universidad Complutense de Madrid para tener una de tipo estudiantes. 20 El acceso a la parte de OpenAI es muy solicitado, por eso para obtener acceso a los elementos se debe rellenar un formulario [24] y esperar la respuesta del equipo encargado. Tras recibir el acceso al entorno de IA, debes realizar distintos pasos siendo estos crear un recurso con el nombre que quieras y rellenar todos los datos que te soliciten en la página. Con el recurso creado, antes de que puedas generar texto o inferencia, necesitas implementar un modelo. Con este modelo creado y vinculado al recurso ya podrás acceder a los datos personales como el API (Application Protocol Interface) keys y el endpoint para lograr las conexiones de tu API. 2.3.3. Hugging Face Hugging Face [25] es una plataforma que proporciona acceso a una amplia gama de modelos de lenguaje, incluidos modelos de código abierto y modelos desarrollados por la comunidad. Ofrece una API para interactuar con estos modelos, lo que permite a los desarrolladores utilizarlos para tareas de procesamiento del lenguaje natural. 2.3.4. Google Cloud Natural Language API Google Cloud [26] ofrece una API de procesamiento del lenguaje natural que proporciona capacidades de análisis de sentimientos, extracción de entidades, clasificación de contenido y más. Aunque no es específicamente un modelo de lenguaje generativo como GPT-3, puede ser útil para muchas tareas de procesamiento del lenguaje natural. 2.3.5. Comparación de plataformas de conexión con LLM Para ilustrar de manera clara las diferencias en los campos más relevantes de las plataformas se presentan los datos en formato tabla, en la cual destacan la calidad del modelo, funcionalidades, facilidades de uso e integración, costo, escalabilidad y soporte y documentación (Tabla 3). 21 Tabla 3: Comparación de plataformas Plataforma Calidad del modelo Funcionalidades Facilidad de uso e integración Costo Escalabilidad Soporte y documentación OpenAI API Alta calidad, destacan por generar texto coherente y relevante Amplia gama, destacan do generació n de texto, traducció n y análisis de sentimient os Fácil y con una document ación clara y ejemplos Puede ser costoso para aplicacio nes de alto volumen Altamente escalable, puede manejar grandes cantidad es de solicitudes Documen tación detallada y soporte técnico Azure OpenAI Services Calidad decente, pero no tan avanzado s como OpenAI Iguales que OpenAI Sencilla con Microsoft Azure, con document ación y ejemplos disponible s Depende del uso y los servicios empleado s, pero puede ser competiti vo Escalable y puede adaptarse Documen tación completa y soporte técnico de Microsoft Hugging Face Dependie nte del modelo seleccion ado, en general una buena calidad Amplia variedad de modelos para el procesami ento de lenguaje natural, pueden requerir configura ción adicional Requiere cierto nivel de técnica para aprovech arla al máximo, comunida d activa y recursos disponible s Forma gratuita Escalabilid ad limitada Documen tación extensa y comunida d activa Google Calidad Amplia Relativam Puede ser Altamente Documen 22 Plataforma Calidad del modelo Funcionalidades Facilidad de uso e integración Costo Escalabilidad Soporte y documentación Cloud Natural Language API razonable, pero más limitada que OpenAI gama, destacan do análisis de sentimient os, extracció n de entidades y análisis sintáctico ente sencilla con otros servicios de Google Cloud, document ación y ejemplos de ayuda alto para aplicacio nes de volumen alto, pero tiene precios flexibles escalable y puede manejar grandes cantidad es de solicitudes tación completa y soporte técnico de Google Cloud Destaca en cada apartado OpenAI API OpenAI API Azure OpenAI Services Hugging Face OpenAI API Azure OpenAI Services La conexión a un LLM en este trabajo ha sido implementada desde VS Code, a través de la plataforma de Azure OpenAI Services. Esta plataforma proporciona una documentación bien detallada con indicaciones paso a paso de cómo conseguir la correcta conexión, así como un método de comunicación con el entorno de la plataforma a través del cual poder mandar cualquier tipo de problema. El hecho de no emplear OpenAI API fue obtener varios errores que no fueron capaces de solucionar. El no uso de Hugging Face se debe a la dificultad de cara a emplear su entorno web y buscar el modelo que se adapte a nuestras especificaciones buscadas y requeridas. En el caso de la plataforma de Google se demanda demasiada información poco oportuna para poder acceder. Por lo tanto, el entorno de conectarse a los LLMs desde aplicaciones de desarrollo propio se encuentra en un punto positivo con varios métodos y accesos desde diferentes plataformas que apoyan a desarrolladores para poder expandir los distintos puntos, así como documentos y webs que te proporcionan los pasos ordenados que se deben de seguir para la correcta implementación. 23 Capítulo 3 - Descripción del plugin para la generación de casos de prueba El desarrollo del plugin se ha llevado a cabo en VS Code dado que este editor de código permite fácilmente la creación de una estructura básica de extensión, de manera automática. Además, es uno de los editores que hemos empleado durante el transcurso de la carrera universitaria y con un gran número de usuarios a nivel mundial. Es compatible con multitud de lenguajes de programación, como Python o C++, entre otros, y cuenta con soporte por parte de una gran comunidad de usuarios y desarrolladores. La extensión implementada se divide en tres fases. En primer lugar, actualizamos un generador heurístico de casos de prueba preexistente creando un método para ejecutar este generador de forma sencilla y con una cantidad mínima de pasos. En segundo lugar, exploramos la conexión y consulta con varios LLM para la generación de casos de prueba. Por último, empaquetamos los dos motores de generación de casos de prueba en un único plugin de VS Code para facilitar su uso por parte de desarrolladores de software. En las siguientes secciones veremos las dependencias y librerías necesarias para el funcionamiento, así como el proceso de desarrollo del plugin. 3.1 Arquitectura del plugin El plugin desarrollado tiene dos claros componentes que son los dos motores, el motor mediante el uso del LLM con el cual tenemos el objetivo de conectarnos con un LLM mediante el uso de API REST y el motor PyMCDC el cual empleamos con el uso de comandos en consola (Ilustración 5). Para esta arquitectura debemos destacar los siguientes componentes principales (Ilustración 6) comenzando por las dependencias, una interfaz de configuración empleando un archivo .json en el cual estarán presentes los parámetros necesarios para configurar el entorno tanto de la parte PyMCDC como del LLM ya que guardamos en este archivo los dos elementos que deben ser más personales como el endpoint y la API key, preparación del entorno en este componente buscamos crear y configurar el terminal así como la activación del pyenv, la generación 30 3.5.1 Generación de casos de prueba mediante LLM: versión 1.0 En cuanto a lo relacionado con generación a través de LLMs comenzamos con la parte de conexión la cual nos resultó complicada, pues no conseguimos una conexión fiable haciéndolo directamente con el servicio ofrecido por OpenAI API, por lo que buscamos otras opciones. Probamos con Dialog Flow y Hugging Face pero no nos resultó cómodo al no dominar las herramientas en cuestión. Terminamos encontrando la plataforma Azure con la cual a través de sus OpenAI services logramos recibir respuestas de un LLM [36]. Las primeras líneas de código relacionadas con este apartado son las dependencias del código que en este caso son las librerías OpenAIClient y AzureKeyCredential siendo esta primera la encargada de permitirnos interactuar con el servicio de Azure OpenAi permitiendo mandar solicitudes al servicio para generar las respuestas que queremos y la segunda para manejar los servicios de credenciales de Azure. Empleamos un archivo con terminación .env que es especialmente útil para manejar de manera segura las configuraciones que pueden variar entre diferentes entornos, en una versión final estos datos pasarían a estar en un archivo con configuración de variables de entorno para encapsular los dos elementos de carácter personal del código, siendo estos el punto de terminación y la API key, proporcionados en el perfil del usuario que haya creado el recurso y el modelo vinculado a él. La lógica principal del código de conexión con un LLM está formada por una lista de mensajes, la cual está dividida en dos partes una será para definir el contexto(rol/role) y la otra el contenido(content) dónde estará el mensaje como tal que queremos enviar/recibir/indicar. Seguido de la creación del cliente empleando la llave proporcionada por Azure, el deployment ID se trata del nombre de la implementación creada en la página de Azure OpenAI Studio, para poder establecer conexión con nuestro recurso llamado test-IA. La siguiente funcionalidad utiliza nuestro modelo de lenguaje para generar respuestas automáticas basadas en la entrada del usuario. Esta entrada está formada 31 por una cadena de texto que hemos creado con anterioridad. Con esto conseguido solo nos falta mostrar las respuestas. Tras varias pruebas en torno a las expresiones booleanas, damos como correcta la extensión creada. 3.5.2 Generación de casos de prueba a través de LLMs: versión 2.0 Para una versión 2.0 se nos recomendó añadir una opción al menú contextual de VS Code con la cual ejecutar la conversación directamente. Para esta idea añadimos un campo contributes a nuestro package.json, en el cual tendremos dos campos, un campo commands en el cual se da nombre al comando que se crea y un campo menus en el cual se indica qué comando será el añadido. Con los comandos y menús definidos en el package.json procedemos a la lógica del comando en este caso al activarse la extensión se registra el comando y se activa por lo tanto a partir de este momento queremos destacar el texto que será la expresión booleana que se mandara como parámetro a la conversación con el chat. Con esta expresión es con la que se ejecutará nuestro código de conexión con Azure. Esto será implementado en una sola extensión juntándose con la generación a través de librerías. Además, tras revisar la información sobre los roles en el apartado de mensajes [37], hemos implementado una mejor estructura. El primer rol que hemos revisado es el rol de sistema (system), que no es obligatorio, pero con el podemos indicar o establecer el comportamiento del asistente en la conversación. En este caso buscamos que sea experto en la generación de casos para expresiones que cumplan el MC/DC , con el rol de asistente (assistant) es el que proporciona las respuestas a la entrada indicada por el sistema y al usuario y lo empleamos para influir en la posterior respuesta del modelo y el último rol empleado es el de usuario (user) con el que se proporciona la entrada para las finalizaciones del chat en este caso le mandamos varios mensajes para indicarle que queremos sobre el criterio MC/DC así como un ejemplo de que formato de salida 32 queremos ante una pregunta del mismo carácter. El rol de función (function) no lo hemos empleado pues no necesitamos saber los resultados de una función. También cabe mencionar los tipos de prompts [38] en Chat GPT, siendo estas herramientas esenciales para guiar la generación de respuestas del modelo los cuales hemos tenido que prestar atención para dotarlos de calidad y una buena construcción, siendo estos empleados en los mensajes generados por cada rol anteriormente mencionados. Siendo los tipos de prompts más destacados: ● Secuenciales, utilizando una secuencia de prompts previos para obtener una respuesta determinada para conseguir una progresión lógica, en nuestro caso empleamos diversos mensajes enviados en rol usuario para que el modelo se adapte al entorno que queremos. ● Estructurales, ayudan a organizar una respuesta del modelo, como en nuestro caso empleamos para pedir que la solución esté en formato de una lista de Python. ● Argumentales, ayuda a que el modelo pueda ofrecer razones o argumentos a favor o en contra, este tipo de prompts no es empleado en nuestro código. ● Comparativos, nos ayudan a obtener respuestas más exhaustivas sobre un sector o ámbito profesional concreto, este tipo se emplea con el rol sistema para dejar claro que se trata de un profesional de la generación de casos base que cumplan el criterio deseado. ● Condicionales, ayudan a poner una condición para obtener una respuesta sobre un tema para conseguir un objetivo concreto, empleamos de forma que le preguntamos si es capaz de darnos el mismo formato de salida que le hemos comentado cuando el usuario le pregunté por una expresión booleana. ● Vacíos o huecos, son aquellos inputs que no contienen información específica o suficiente para guiar la generación de respuestas, pero estos pueden ayudarnos a dar aportar contexto previo, así como nosotros empleamos uno para asegurar que nuestro modelo conoce los motivos para que una generación de casos base sea correcta. 33 Para una comparación de tiempo entre los generadores se cronometra el tiempo desde el inicio de la ejecución (PyMCDC)o conversación (LLM) hasta la devolución de la solución, incluyendo el tiempo necesario para ejecutar los intentos en el caso que el LLM fallara con el cálculo inicial. Observando las salidas generadas vemos que a pesar de que al LLM se le pide explícitamente que responda únicamente la respuesta deseada, es decir, la lista en formato JSON con los casos de prueba. Muchas veces responde con algo más de texto, ya sea una muy breve introducción o alguna anotación. Por ello, y para asegurar que la salida que se muestra al usuario por los mensajes informativos de VS Code, creamos una sencilla función que lee la salida obtenida por la IA y obtiene de ella únicamente la lista con los casos de prueba. El siguiente diagrama (Ilustración 7) muestra los pasos que sigue la ejecución de esta extensión para lograr la conexión. Comenzando por la obtención de la API key y el endpoint sacados de Azure, a continuación, se crea la lista de mensajes que queremos enviar al asistente, diferenciando los tres roles que pueden ser los mensajes y junto a esto el deployment id ya solo falta recibir la respuesta del asistente. 34 Ilustración 7: Extensión LLM Versión 2.0 3.5.3 Generación de casos de prueba a través de LLMs: versión final Para esta última versión ya estando ambas generaciones en un mismo plugin, buscamos mejorar aún más la respuesta del LLM (Ilustración 8), dado que en la anterior versión no proporcionan soluciones que consideramos acertadas. A esto se une el hecho de que no estamos seguros de que las respuestas generadas sean capaces de cumplir los criterios específicos de la cobertura de MC/DC que han sido mencionados anteriormente. Para esto hacemos que reciba información de vuelta, en caso de ser errónea la respuesta dada, esto será un messages2 formado por los mensajes presentes en messages unidos con dos mensajes nuevos que son has fallado en tu respuesta y otro mensaje que le mandara el motivo de su fallo. 35 Al ser comprobada a través de un script comprob.py en el cual se mira si la respuesta cumple estas dos condiciones: 1) El número de casos de prueba generados está entre n+1 y 2n 2) Toda variable tiene un caso de prueba para cierto y otro para falso. Este script tiene cuatro salidas posibles, siendo True si ambas condiciones son respetadas, 1 si falla en la primera condición, 2 si falla en la segunda condición y 3 si falla en ambas. Con estas salidas hacemos al chat generar otra respuesta sabiendo en qué ha fallado para así mejorar la salida, limitando esto a tres intentos. Por lo tanto ahora la salida con la lista de casos solo se mostrará en caso de ser correcta en otro caso se mostrará un mensaje de generando casos y si se llega al límite de tres intentos realizados se mostrará un mensaje de límite alcanzado y no tendremos por lo tanto respuesta. 36 Ilustración 8: Arquitectura final de la extensión LLM 3.6 Desarrollo de la extensión para generar automáticamente casos de prueba a través de otros motores heurísticos (PyMCDC) Para la parte de la extensión que se basa en PyMCDC partimos del código Python que se nos entregó al comienzo del trabajo de fin de grado y que es la base de esta funcionalidad. La idea principal es poder interactuar con este programa desde nuestra extensión para Visual Studio Code, para poder trabajar con él de una manera más cómoda y efectiva, mejorando así la experiencia de los usuarios. Lo primero que tuvimos que hacer fue crear un entorno pyenv a través de la herramienta Windows Subsystem for Linux (WSL) en el que se encontraran todas las librerías y herramientas necesarias para poder ejecutar el código PyMCDC. Ya con el 37 entorno creado, funcionando correctamente y tras varias pruebas del programa realizadas empezamos a trabajar en la extensión. La gran ventaja de Visual Studio Code es su capacidad de poder ejecutar toda clase de terminales que se encuentren instaladas en el ordenador, por lo que comunicarse con nuestro entorno WSL era una tarea sencilla. Debíamos crear una terminal WSL y activar nuestro entorno en ella para poder ejecutar el programa con la entrada deseada. Al comienzo de la ejecución de la extensión se llama a una función para preparar el entorno. La función recibe una serie de datos obtenidos previamente de la lectura de un fichero de configuración. Entre estos datos se encuentran: el nombre que el usuario desee darle al terminal, la shell que debe usar (WSL), el nombre del entorno pyenv creado por el usuario y la ruta al directorio donde se encuentran los archivos de la extensión y al final han sido incluidos la API key del LLM y el endpoint. Con estos datos se crea un terminal WSL, se activa el entorno y se dirige a la ruta indicada dejando el entorno preparado para su uso. Lo siguiente que hicimos fue un programa Python que sirviera de entrada a PyMCDC para poder ejecutarlo con los argumentos deseados. Es decir, un programa que obtenga unos argumentos y ejecute PyMCDC haciendo uso de dichos argumentos. Además, se creó una función Typescript para poder mandarle el comando de ejecución del programa Python mencionado con la entrada deseada a la terminal WSL del entorno. Esta función también almacena la respuesta de la terminal en un fichero out.txt que se lee para poder mostrar la salida obtenida a través de un mensaje informativo de VS Code. Con esto ya teníamos todo preparado para desarrollar los comandos necesarios para hacer uso de PyMCDC desde nuestra extensión. Creamos dos comandos. El primero permite al usuario escribir manualmente en una inputbox la expresión condicional deseada desde la barra de comandos de Visual Studio Code. 38 Y el segundo que utiliza el selector de texto para que el usuario seleccione la expresión deseada desde el código en el que esté trabajando y que esta sirva como argumento para nuestro programa, a continuación, el usuario haría clic derecho en el ratón para ejecutar el comando de la extensión. Para finalizar, registramos estos comandos en el package.json de la extensión y creamos un acceso directo a los mismos al pulsar el botón derecho del ratón para una mayor comodidad de acceso al comando. De esta forma el usuario tiene dos opciones para ejecutar la funcionalidad PyMCDC de nuestra extensión y que opte por la que desee. 3.7 Extensión final El código que está presente y accesible en el directorio de GitHub representa la fusión de las dos extensiones explicadas en una sola entidad. Nuestro propósito era emplear los dos generadores desde la misma extensión y logramos este objetivo integrando los elementos presentes en la extensión de conexión al LLM en la extensión de ejecución de PyMCDC, pues esta posee un mayor grado de desarrollo. El proceso de integración fue fluido y fácil, pues desde un inicio realizamos las extensiones con la idea de culminar en una unión final. 3.8 Ejemplo de ejecución. Para hacer uso de la extensión final la cual tiene los dos generadores implementados, el proceso a seguir sería el siguiente (Ilustración 9). El usuario tendría instalada la extensión en el Visual Studio Code de su equipo. 39 Ilustración 9: Esquema de ejecución de la extensión Supongamos que el usuario está trabajando en el código de un proyecto y, a la hora de depurarlo y testearlo requiere de casos de prueba que cumplan los condicionales que se encuentran en las diferentes secciones de su código. El usuario utilizará el selector de texto sobre la condición para la que desea generar los casos de prueba. Una vez seleccionada, el usuario hará clic derecho en el ratón para mostrar el menú contextual. En él verá dos opciones: “Generate testcases (LLM)” y “Generate testcases (PyMCDC)” (Ilustración 10). Estas opciones como se indica en su nombre tienen la función de generar los casos de prueba para la condición seleccionada mediante el uso de un LLM y la librería PyMCDC respectivamente. 46 Expresión/Salida librería/Salida LLM Número de casos generados/Númer o de casos esperados Intentos hasta respuesta válida (LLM) Tiempo de ejecución Cumple la comprobación Salida de LLM 6 / 5 2 / 3 813(ms) SI EJEMPLOS DE TCASII Expresión (a>2) & (c>2) & ((d>3) | (e>9)) & (h>1) | (a>2) & (d>3) | (e>9) & (i<1) | (b>12) & (e>9) | (f>1) Salida de la librería 9 / 9 128008 (ms) Salida de LLM X / 9 3 / 3 92509 (ms) NO Expresión ((a>10) & (c>10) | (b>11) & (d>2)) & (e>21) & ((f>1) & (g>8) | (i<1) & (h>6)) Salida de la librería 10 / 10 160561 (ms) Salida de LLM X / 10 3 / 3 135885 (ms) NO Expresión ((a>1) & (c>2) | (b>3) & (d>1)) & (e>4) & ((f>8) | ((i>2) & ((g>2) & (j>8) | (h>5) & (k>7)))) Salida de la librería 12 / 12 204047 (ms) Salida de LLM 15 / 12 1 / 3 165229 (ms) SI 47 Expresión/Salida librería/Salida LLM Número de casos generados/Númer o de casos esperados Intentos hasta respuesta válida (LLM) Tiempo de ejecución Cumple la comprobación Expresión (a<10) & ((b<1) | (c<1)) & ((d>10) | (e<12)) Salida de la librería 6 / 6 228858 (ms) Salida de LLM 7 / 6 3 / 3 423308(ms) SI Expresión (e<2) & (f>3) & (g<9) & (a>3) & (((b>8) & (c>67)) |((h<8) & (d>4))) Salida de la librería 9 / 9 247553 (ms) Salida de LLM X / 9 3 / 3 519563 (ms) NO Expresión (a>1) & (b<1) & (c<1) & (d<1) & (e<1) & (f>1) & ((g>1) | (n<1) & ((h>1) | (i>1))) & ((j<1) | (k<1) & ((j>1) | (l<1)) & (m<1)) Salida de la librería 14 / 14 264444 (ms) Salida de LLM X / 14 3 / 3 579929 (ms) NO Expresión (a>1) | (b>1) | (c>1) | (m<1) & (d<9) & (e>1) & (f>1) & (g<2) & (h<3) | (i>2) & ((j>2) | (k>3)) & (l>2) Salida de la librería 14 / 14 283575 (ms) Salida de LLM X / 14 3 / 3 633248 (ms) NO 48 Expresión/Salida librería/Salida LLM Número de casos generados/Númer o de casos esperados Intentos hasta respuesta válida (LLM) Tiempo de ejecución Cumple la comprobación Expresión ((c<2) | (d<5)) & ((e<10) & (f>1)) & (g<9) & (a<13) & ((b>5) & (i>0) | (h<2) & (k>23)) Salida de la librería 11 / 11 304042 (ms) Salida de LLM X / 11 3 / 3 683122 (ms) NO 4.1. Casos destacados En este apartado se menciona en especial dos casos que se han encontrado en la comparación siendo “masking MC/DC” y no tener respuesta por parte de PyMCDC pero sí del LLM. Este primero conocido como "masking MC/DC" o "MC/DC enmascarado” ha estado presente en el momento de transformar los ejemplos extraídos de TCAS II, dado que en la mayoría de las expresiones se daban. Un ejemplo es (f & g | ~f & h), porque los valores de verdad que toma f afectan a ~f y por tanto los cuatro términos booleanos de la expresión no son completamente independientes. PyMCDC no nos proporciona una respuesta con casos base, sino una lista vacía por lo tanto se ha tenido que modificar de manera que la negación no esté presente, un ejemplo sería (f & g | ~i & h) en el que cambiamos ~f por ~i añadiendo una nueva variable, pero esta no es dependiente a otra. El caso de no tener respuesta por parte de PyMCDC, pero sí del LLM se ve en la expresión ((x > 0) & (y < 0)) & ((x < 0) & (y > 0)), esta expresión para PyMCDC nos da como respuesta, Solving [(! (0 < y)), (0 < x), (y < 0), (x < 0)] with False. Domain is not SAT!!! [], se observa que devuelve que el dominio de las variables no satisface las restricciones 49 proporcionadas, pero para el LLM sí que hay solución. Formada por cuatro casos base la cual podemos descartar directamente por no cumplir MC/DC, pero a la vez al observar la expresión nos damos cuenta de que es imposible que un número sea a la vez mayor que 0 y menor que 0 por lo tanto cualquier respuesta va a ser errónea. Puesto que esta expresión no posee una solución que, de verdadero, pero para el LLM parece que no se contempla en ningún caso que una expresión no tenga respuesta. También mencionar la negativa del LLM de generar de manera directa una respuesta correcta para los casos más complejos, como en este caso representan los modificado de TCAS II, necesitando en todos ellos mínimo dos intentos de generación. 4.2. Comentario final Tras observar estos casos, se puede concluir que la generación a través de la librería se encuentra un paso por delante de la generación mediante modelos de lenguaje. Esto se debe a que los modelos de lenguaje cometen fallos en expresiones, especialmente en las complejas, así como en distintas ocasiones tienen dificultades para sacar una solución que se adapte al criterio buscado. Además, emplean la volatilidad, es decir puede ocurrir que al solicitar más de una vez solución para una expresión la respuesta varíe. También debemos destacar la velocidad, a pesar de ser los dos métodos muy rápidos, la ejecución a través del LLM es mucho más lenta. Se ha tomado en cuenta el tiempo de finalización de la ejecución, considerando la posibilidad de no obtener una respuesta correcta en el caso de la generación mediante LLM. Esto no implica que el generador mediante LLM deba descartarse por su alta latencia, ya que este aspecto puede mejorarse trabajando con un micro contenedor o una imagen local embarcado junto con el resto del plugin de VS para que las ejecuciones fluyan más rápido. Sin embargo, los LLM actuales consumen muchos recursos de CPU, por lo que es más común que los usuarios accedamos a ellos como servicios web. Por el contrario, queremos destacar en positivo la posibilidad de evaluar expresiones de tipo booleano dado que su contraparte es incapaz de ejecutar estas 50 expresiones por lo tanto es un punto para tener en cuenta en esta nueva forma de generar casos de prueba. Por último, tras realizar esta comparación en distintos equipos, se debe mencionar la diferencia positiva hacia el generador mediante LLM, la cual es la facilidad y accesibilidad de uso, pues para emplear PyMCDC debemos tener el entorno de WSL instalado correctamente con todas sus dependencias lo cual dificulta su uso. 51 Capítulo 5 - Conclusiones y trabajo futuro La generación de casos de prueba mediante modelos de lenguaje es posible incluso positiva, empleándose de manera rápida y fácil para cualquier tipo de usuario. Debemos destacar esta generación para expresiones de poca complejidad o de dificultad baja, dado que para expresiones de media/alta complejidad es observable que su empleo no conlleva una buena respuesta. Consideramos que la generación mediante LLM está condicionada por el entorno de estos modelos de lenguaje, que bien están desarrollados de gran manera para unos entornos, para este caso no consideramos que en la última versión disponible hasta la fecha el gpt-3.5-turbo sea un buen elemento para trabajar, dado que debe ser más desarrollado para ser capaz de realizar una respuesta correcta ante cualquier nivel de expresión, dando igual su complejidad, cosa que ahora mismo no puede hacerse, Debes de establecer un conjunto de mensajes muy concreto y mandar un numero de mensajes elevado para darle un conocimiento cercano lo más posible al entorno MC/DC para conseguir así establecer conversación con un chat capaz de responder de forma adecuada y ni con esta técnica empleada de manera correcta parece que se pueda lograr. La falta de confianza ante el conocimiento de este entorno del MCDC provoca que seamos nosotros los que tenemos que realizar una comprobación sobre las hipotéticas soluciones correctas que nos proporciona, dado que no nos permite estar seguros de que se tomen respuestas como correctas que no tienen nada que ver con lo que se está buscando. En conclusión, buscando la eficacia y correctitud la generación de casos de prueba mediante modelos de lenguaje está un paso por detrás de lo deseado. Siendo más destacable la generación empleando la librería frente a esta generación, pero como hemos dejado reflejado en esta memoria cada generación tiene sus puntos positivos y negativos y tenemos claro que este proyecto podría mejorar con el propio desarrollo del entorno de los modelos de lenguaje. 52 5.1. Trabajo a futuro Tras realizar esta introducción a la generación automática a través de este nuevo entorno conocido como son los LLMs, hemos identificado limitaciones y áreas que consideramos deben ser los próximos pasos a realizar para consolidar este proyecto siendo estas la realización de una función más crítica y selecta de comprobación para salida de LLM puesto que la realizada es una con dos criterios tomados de forma básica y esto puede llevar a ciertos errores así como la implementación de un sistema para que el propio chat no forme respuestas para expresiones que no tienen solución. También hemos de mencionar el desarrollo de una mejora del apartado visual de la extensión, así como mejorar su comportamiento en cuanto rapidez de ejecución. En cuanto al área de conexiones con LLM basándonos en las conclusiones de este estudio sería positivo poder realizar distintas conexiones a varios entornos LLM diferentes, para poder decidir cuál de todos es el más avanzado para generar estos casos de prueba y cual trabaja mejor con el criterio MC/DC. En resumen, las propuestas de investigación futura presentadas en esta sección son positivas para avanzar en el conocimiento sobre la generación de casos de prueba mediante modelos de lenguaje y tienen el potencial de influir en el futuro y en el desarrollo de nuevas tecnologías. 53 Introduction Motivation Currently, in the world of software development, there is a great diversity of increasingly complex programs with a critical impact on society in case of failure (e.g., think of the banking sector, communications, or transportation). Therefore, these systems require minimum levels of quality and reliability to ensure their proper functioning. The need to develop software that meets these standards has made software testing a vital part of the development process of any software program. The goal of testing is to find and correct errors, ensuring higher quality of the developed software and reducing the maintenance cost, thus guaranteeing user satisfaction. To achieve this goal, the main tool of the software tester is the tests, which consist of a tuple of input values as well as the expected output value. This tuple of (input values, expected output) is called a test case, and it is the most important part of any test because it serves to challenge the program's code in specific scenarios to evaluate its behavior in all kinds of situations, from the most common to the most complex. The effectiveness of these test cases lies in their ability to find faults, thereby ensuring the correct functioning of the program in any situation. These test cases are designed following certain coverage criteria, that is, a series of metrics and approaches to measure the parts that have been executed during the tests. Therefore, these criteria must be effective to ensure adequate coverage of all parts of the software and effectively identify faults in the code. The effort and difficulty in the manual creation of test cases have increased along with the current complexity of programs, making it an arduous task that is more prone to errors. This results in exhaustive testing having a high economic and time cost. Being aware of this problem, a solution is proposed: the automatic generation of test cases, which aims to optimize the important task of software testing by speeding up the process of creating test cases and increasing their quality. 54 In this TFG (Final Degree Project), we explore the automatic generation of test cases using Large Language Models (LLMs) under the MC/DC coverage criterion, a special type of branch coverage. This criterion is used in industrial standards (aerospace sector, DO-178C standard, and automotive sector, ISO 26262 standard) to ensure the reliability and safety of software products implemented in the aerospace and automotive sectors, respectively. These standards address everything from software development processes to quality and safety management. Failures are classified according to their severity, allowing their prioritization in tests to achieve the highest possible reliability and safety. When executing the tests, using the MC/DC coverage criterion ensures greater sensitivity to branch coverage. Additionally, test sets that satisfy the MC/DC criterion are much smaller than those that meet branch coverage criteria. Therefore, the time required to execute the tests is drastically reduced while increasing their effectiveness. However, achieving a minimal (optimal) set of tests that satisfy the MC/DC criterion is costly and difficult, so approximations are usually achieved. To overcome this limitation, a heuristic has been proposed to approximate test generation with the MC/DC criterion using LLM platforms. This offers an easy way to generate effective test cases with the aim of optimizing the software testing process, increasing software quality, and making testing a less costly task in terms of time and money. Goals • The main objective of this Final Degree Project is the automatic generation of test cases using language models. To achieve this primary objective, a series of specific goals must be met: Acquisition of knowledge and various information resources about the MC/DC coverage criterion, to understand the extent to which our automatic development has been positive or negative. • Updating and improving a pre-existing heuristic tool for generating test cases that satisfy MC/DC criteria. 55 • Implementation of an extension/module in VS Code for the automatic generation of test cases through connection with an LLM. • Implementation of a plugin for a development environment (IDE) that facilitates the use of the test case generation tool by non-expert users and encapsulates the two previously mentioned test case generation engines (LLM-based generator and pre-existing heuristic tool generator). In particular, the VS Code editor has been chosen as the IDE to host the plugin. • Comparison of outputs from both test case generators concerning the MC/DC criterion to assess the quality of our automatic generation using LLM. With this set of objectives correctly carried out, it will be possible to ensure that the main objective has been achieved. Work plan For the development of this project, a hybrid methodology called Scrumban will be used. This combines elements of the Scrum methodology, focusing on delivering progress in short cycles, which is why we will use the Jira Software platform (Illustration 16). On this platform, a structure divided into sprints will be created, and the Kanban methodology will be incorporated, as the platform allows us to view a board showing the status of tasks and the development flow itself. The work structure will be divided into different sprints, which will initially be set to a basic duration of one week. This period can be adapted based on the number of tasks/works to be done. After this time, meetings with the tutors will be held to show the progress made, finalize the current sprint, and start the next one. The amount of work in each sprint will be represented through tasks grouped by categories (Illustrations 17 and 18). These tasks can be created by the tutors or by the students. The tasks can move through five states: • To do • In progress • Under review 62 can lead to errors. Additionally, implementing a system to prevent the chat from generating responses for expressions that have no solution is necessary. We should also mention the development of an improved visual aspect of the extension, as well as enhancing its execution speed. Regarding LLM connections, based on the conclusions of this study, it would be beneficial to establish connections to various LLM environments to determine which is the most advanced for generating these test cases and which works best with the MC/DC criterion. In summary, the future research proposals presented in this section are positive steps towards advancing knowledge in the generation of test cases using language models. They have the potential to influence the future and the development of new technologies. 63 Capítulo 6 - Contribuciones personales Ismael Barahona Cánovas Desde que decidimos realizar el TFG en conjunto con mi compañero Gonzalo Contreras Gordo, hemos estado enfocados en encontrar algo que nos llamara la atención y nos motivará a ambos para poder trabajar de manera activa en ello. Por este motivo seleccionamos este trabajo dado que la inteligencia artificial es un apartado tecnológico que nos llama la atención, así como conocer más sobre ella dado que en las propias asignaturas de la carrera se dan temas. Pero en ninguna se habla de manera extensa sobre un tema tan puntero como los LLMs. Ya con el proyecto en marcha tenía claro que quería reuniones con los tutores de manera asidua pues considero que me deben guiar y dar opinión conforme se vaya avanzando. Plantee la opción de ponernos un horario fijo de trabajo para el proyecto con mi compañero, el cual seguimos salvo en casos de excesivo trabajo. Para comenzar con el proyecto he tenido que repasar los elementos básicos del lenguaje Python pues es un lenguaje con el que apenas he trabajado. Tuve que buscar información para poder comprender el código inicial proporcionado. Con estas bases pasé a buscar y leer información para entender las bases sobre el criterio de cobertura que dirige este trabajo el MC/DC el cual era nuevo para mí. No me costó comprender en qué consiste y cuál es su relevancia, así como qué objetivo puede tener el correcto desarrollo de la generación automática mediante LLM. En cuanto al desarrollo del código de la extensión creada me encargue del entorno relacionado con la conexión al LLM, comenzando con la búsqueda de información relativa, así como de la prueba de distintos entornos. Esto debo decir que me resultó positivo pues como he mencionado es un entorno que me gusta y despierta mi curiosidad, desarrollé el código en Typescript, un lenguaje nuevo para mi pues como tal no se emplea en ninguna asignatura cursada. También he tenido que relacionarme con el entorno de WSL para probar la parte de la librería de PyMCDC. 64 Del entorno de las extensiones de Vs Code he tenido que informarme para poder comprobar el correcto desenlace de la conexión. Esto no ha hecho más que animar mi interés por esta rama de tecnología, que ya tenía mi atención pues realice la asignatura optativa inteligencia artificial aplicada al control. En el entorno de la extensión en la que se unen ambos generadores he participado activamente en mejoras e implementaciones de nuevo código necesario. Pero la parte que más me ha absorbido es la comparación de salidas, pues teniendo un generador tan preciso como lo es el de la librería, permite la comparación con lo creado por el LLM, entonces todo este apartado ha sido mi ocupación personal, lo cual nos ha ayudado a observar las conclusiones de manera clara. En la memoria diría que he tomado el rol principal pues es algo que me gusta ya que no tengo problema en redactar cualquier avance o problema observado pues soy una persona que considera que todo lo que se realice en un proyecto debe estar reflejado en algún entorno. Los capítulos, así como sus secciones han sido redactados y supervisados por ambos elementos del equipo, siendo claro que puede que alguno haya desarrollado más un capítulo o otro ya fuese por ser del entorno que había profundizado más, siendo esto presente en el capítulo de la extensión, o bien porque a alguien le interesaba más ese capítulo, como en mi caso sería el apartado de entorno de conexiones con LLMs. En resumen, mis contribuciones a este proyecto han sido variadas e integrales, abarcando desde la planificación hasta la redacción final. Estas experiencias me han permitido desarrollar habilidades esenciales en el campo de la inteligencia artificial, así como en el entorno de los LLMs, y han sido fundamentales para mi desarrollo académico. 65 Gonzalo Contreras Gordo A la hora de matricularme para hacer el TFG, tenía claro que quería trabajar con mi compañero Ismael Barahona Cánovas ya que la gran mayoría de trabajos y proyectos que ha habido que hacer en las asignaturas los hemos hecho juntos, nuestra metodología de trabajo y de enfocar las cosas es similar por lo que trabajamos bien juntos. Como no teníamos ningún tema en específico en el que quisiéramos trabajar decidimos buscar entre los temas propuestos por los profesores. Lo que sí teníamos claro era que queríamos trabajar sobre algún tema que nos llamara la atención de una forma u otra, ya sea por el tema en sí, su objetivo o el ámbito en el que se centra. Vimos este tema y nos interesó el uso de la inteligencia artificial y los LLMs, ya que es un tema muy actual y con bastante potencial, por lo que nos decidimos a explorar este tema. Al comienzo del desarrollo del TFG y las primeras reuniones con los tutores empezamos a informarnos sobre diferentes temas relacionados, como el mundo del testing para comprender su importancia y los diferentes criterios de cobertura que se emplean para crear los tests de los programas, en nuestro caso, el criterio MC/DC. Los tutores también nos proporcionaron el código inicial para la generación de casos de prueba a través de PyMCDC por lo que también tuvimos que repasar el lenguaje Python y comandos del entorno Linux. Esta parte introductoria fue común a ambos miembros del equipo pues los dos necesitábamos la base para poder trabajar en ello. Para el desarrollo de la extensión yo investigué el entorno de Jupyter Notebooks en el proceso de decisión del entorno para el que desarrollaríamos la extensión, finalmente decidimos usar Visual Studio Code. Así que para empezar la implementación tuve que informarme y aprender a manejar Typescript, un lenguaje de programación que no habíamos usado nunca. En el desarrollo de la extensión yo me encargué de la base de esta, es decir, los comandos para ejecutar las diferentes funcionalidades de la extensión, la función de activación y, en resumen, las partes básicas de la extensión. 66 En mi caso, me centré en la parte de generación de casos de prueba mediante la librería PyMCDC. Tuve que investigar una manera de poder ejecutar desde nuestra extensión código en Python en un entorno virtual Linux, crear un programa de entrada al código de generación de casos y transmitir los resultados obtenidos a la interfaz de Visual Studio Code para verlos cómodamente. Tanto Ismael como yo trabajamos en conjunto en numerosas mejoras y funciones una vez que nuestras respectivas partes de la extensión se encontraban en la versión completa. Respecto a la redacción de la memoria y creación de diagramas y figuras, ambos integrantes del equipo hemos participado en la gran mayoría de las secciones de esta, a excepción de aquellas partes relacionadas con nuestra respectiva aportación e implementación de la extensión. Para resumir, la mayoría de mis aportaciones en este trabajo se encuentran en el código de la extensión, así como en la muchas de las secciones de esta memoria, destacando aquellas relacionadas con la librería PyMCDC. Este trabajo me ha permitido aprender sobre las características, el funcionamiento y el entorno de los LLMs que actualmente están en boca de todos. También he aprendido nuevas formas de utilizar el lenguaje Python para aplicaciones en la inteligencia artificial, así como aprender a manejar código en Typescript y desarrollar programas en entornos de trabajo que no había usado anteriormente y que ahora ya forman parte de mis conocimientos académicos. 67 Bibliografía [ 1] B. Broekman y E. Notenboom, «Testing embedded software,» 2003. [En línea]. Available: https://books.google.es/books?hl=es&lr=&id=O3hpTaXmHKwC&oi=fnd&pg=PR10& dq=testing+de+software&ots=8f7ynPWRiP&sig=jySvp2o0QchaKNcB6vpvoFPYFAc&r edir_esc=y#v=onepage&q=testing%20de%20software&f=false. [Último acceso: Junio 2024]. [ 2] G. J. Myers, «The Art of Software Testing,» 2004. [En línea]. Available: http://www.51testing.com/N_download/lib/TestingTechDL/ArtofSoftwareTesting.p df. [Último acceso: Junio 2024]. [ 3] «Wikipedia LLM,» [En línea]. Available: https://es.wikipedia.org/wiki/Modelo_de_lenguaje_grande. [Último acceso: Junio 2024]. [ 4] K. Hayhurst, D. Veerhusen, J. Chilenski y L. Rierson, «A Practical Tutorial on Modified Condition/ Decision Coverage,» 2001. [En línea]. Available: https://shemesh.larc.nasa.gov/fm/papers/Hayhurst-2001-tm210876-MCDC.pdf. [Último acceso: Junio 2024]. [ 5] L. A. Johnson, «DO-178B: Software considerations in airborne systems and equipment certification.,» 1998. [En línea]. Available: https://www.dcs.gla.ac.uk/~johnson/teaching/safety/reports/schad.html. [Último acceso: Junio 2024]. [ 6] «ISO 26262,» 2024. [En línea]. Available: https://es.wikipedia.org/wiki/ISO_26262. [Último acceso: Junio 2024]. 68 [ 7] Atlassian, «Jira Software,» [En línea]. Available: https://www.atlassian.com/es/software/jira. [Último acceso: 2024]. [ 8] «Pagina oficial de Python,» [En línea]. Available: https://www.python.org/. [Último acceso: Junio 2024]. [ 9] https://www.typescriptlang.org/, «Pagina oficial Typescript,» [En línea]. Available: https://www.typescriptlang.org/. [Último acceso: Junio 2024]. [ 10] G. Bierman, M. Abadi y M. Torgersen, «Understanding typescript,» 2014. [En línea]. Available: https://link.springer.com/chapter/10.1007/978-3-662-44202-9_11. [Último acceso: Junio 2024]. [ 11] craigloewen-msft, mattwojo, suelsp, Soham-glitch, donwilson y wibjorn, «Instalación de Linux en Windows con WSL,» [En línea]. Available: https://learn.microsoft.com/es-es/windows/wsl/install. [Último acceso: 2024]. [ 12] G. Contreras y I. Barahona, «Github proyecto TFG,» UCM, Junio 2024. [En línea]. Available: https://github.com/TGF-2023-24/testing-ai/tree/pruebas. [Último acceso: Junio 2024]. [ 13] G. J. Myers, C. Sandler y T. Badgett, The art of software testing, 2011. [ 14] F. Ahishakiye, J. I. Requeno, V. Stolz y L. M. Kristensen, «Coverage Analysis of Net Inscriptions in Coloured Petri Net Models,» 2020. [En línea]. Available: https://pdfs.semanticscholar.org/175f/b6f4faeb3b5ffc8bf6b3242cf8dea0eb0e88.p df. [Último acceso: Junio 2024]. [ 15] H. Manvar y A. S. Raina, «LLM Everywhere: Docker for Local and Hugging Face Hosting,» 2023. [En línea]. Available: https://www.docker.com/blog/llmdocker-for-local-and-hugging-face-hosting/. [Último acceso: Junio 2024]. 69 [ 16] F. Ahishakiye, J. I. Requeno Jarabo, L. Michael Kristensen y V. Stolz, «Repositorio GitHub py-mcdc,» 2021. [En línea]. Available: https://github.com/selabhvl/py-mcdc. [Último acceso: Junio 2024]. [ 17] K. Ghani y J. A. Clark, «Automatic test data generation for multiple condition and MCDC coverage,» de Fourth International Conference on Software Engineering Advances , IEEE, 2009, pp. 152-157. [ 18] T. Kitamura, Q. Maissonneuve, E.-H. Choi, C. Artho y A. Gargantini, «Optimal test suite generation for modified condition decision coverage using SAT solving.,» 2018. [En línea]. Available: https://doi.org/10.1007/978-3-319-99130-6 9. [Último acceso: Junio 2024]. [ 19] J.-R. Chang y C.-Y. Huang, «A study of enhanced MC/DC coverage criterion for software testing.,» de 31st Annual International Computer Software and Applications Conference, IEEE, 2007, pp. 457-464. [ 20] A. Victoria Alcaraz, G. Espejel Salazar y E. G. Cossio Franco, «Generación automática de casos de prueba a partir de requerimientos funcionales utilizando gramáticas libres de contexto,» 2021. [En línea]. Available: http://ciateq.repositorioinstitucional.mx/jspui/handle/1020/511. [Último acceso: Junio 2024]. [ 21] M. Azure, «Pagina oficial de OpenAi API,» Azure, [En línea]. Available: //openai.com/product. [Último acceso: 05 2024]. [ 22] «OpenAI documentation,» OpenAI, [En línea]. Available: https://platform.openai.com/docs/overview. [Último acceso: 2024]. [ 23] M. Azure, «Pagina oficial de Azure OpenAI,» Azure, [En línea]. Available: https://oai.azure.com/portal/af9bc2a0874d4f129812b5ed7f0712ff/deployment. [Último acceso: 05 2024]. 70 [ 24] M. Azure, «Acceso a azure-portal,» [En línea]. Available: https://aka.ms/oai/access?azure-portal=true. [Último acceso: 05 2024]. [ 25] «Pagina oficial Hugging Face,» [En línea]. Available: https://huggingface.co/. [Último acceso: 2024]. [ 26] Google, «IA de Natural Language(Google),» [En línea]. Available: https://cloud.google.com/natural-language?hl=es_419. [Último acceso: 2024]. [ 27] C. Drake, «Python EDA Documentation,» 2018. [En línea]. Available: //pyeda.readthedocs.io/en/latest/. [Último acceso: Junio 2024]. [ 28] A. Micheli y M. Gario, «PySMT,» [En línea]. Available: https://pypi.org/project/PySMT/. [Último acceso: Junio 2024]. [ 29] J. Grant, «Python Sorted Containers,» 2014. [En línea]. Available: https://grantjenks.com/docs/sortedcontainers/. [Último acceso: Junio 2024]. [ 30] B. Bayles y E. Rose, «more-itertools,» 2012. [En línea]. Available: https://pypi.org/project/more-itertools/. [Último acceso: Junio 2024]. [ 31] S. C. Johnson, «Lint, a C program checker.,» 1977. [En línea]. Available: http://squoze.net/UNIX/v7/files/doc/15_lint.pdf. [Último acceso: Junio 2024]. [ 32] F. Ahishakiye, J. I. Requeno Jarabo, L. M. Kristensen y V. Stolz, «Mc/dc test cases generation based on bdds. In International Symposium on Dependable Software Engineering: Theories, Tools, and Applications,» 2021. [En línea]. Available: https://link.springer.com/chapter/10.1007/978-3-030-91265-9_10. [Último acceso: Junio 2024]. [ 33] T. Anderson y M. Dahlin, de Operating Systems: Principles and Practice, Recursive Books, 2014, p. 123. 71 [ 34] «Pagina VS Code,» Microsoft, [En línea]. Available: https://code.visualstudio.com/. [Último acceso: Junio 2024]. [ 35] «Pagina Jupyter,» [En línea]. Available: https://jupyter.org/. [Último acceso: Junio 2024]. [ 36] mrbullwinkle, nitinme, mgreenegit, dbradish-microsoft, v-alje y eric-urban, «Quickstart: Get started generating text using Azure OpenAI Service,» Microsoft Azure, 2023. [En línea]. Available: https://learn.microsoft.com/en-us/azure/aiservices/openai/quickstart?tabs=command-line%2Cpython&pivots=programminglanguage-javascript. [Último acceso: Junio 2024]. [ 37] Hugo, «Getting Started with ChatGPT API: A Comprehensive Guide,» 2023. [En línea]. Available: https://aneejian.com/getting-started-chat-gpt-apicomprehensive-guide/. [Último acceso: Junio 2024]. [ 38] A. Fernández, «Tipos de Prompts en ChatGPT y cómo utilizarlos para mejorar los resultados,» [En línea]. Available: https://es.linkedin.com/pulse/tipos-deprompts-en-chatgpt-y-c%C3%B3mo-utilizarlos-para-amel-fern%C3%A1ndez-. [Último acceso: 2024].