-
Introducción
La clase 16 marca el cierre de un proceso de aprendizaje progresivo enfocado en el desarrollo de habilidades prácticas de programación a través de un proyecto integrador. A lo largo de las clases anteriores, los estudiantes construyeron, paso a paso, una calculadora avanzada, aplicando conocimientos esenciales sobre variables, estructuras de control, funciones, modularidad, manejo de archivos y robustez del software. Esta última clase tiene como propósito consolidar todo ese conocimiento mediante la revisión y validación del sistema completo, evaluando tanto su funcionalidad técnica como su calidad estructural y experiencia de uso.
En este módulo final, además de integrar todos los componentes del proyecto, se introduce un enfoque crítico hacia la calidad del software mediante pruebas sistemáticas. Se abordan distintos tipos de pruebas: unitarias, de integración, de manejo de errores y de usabilidad, las cuales permitirán verificar que cada parte del programa funciona correctamente tanto de forma independiente como en conjunto. Asimismo, se reflexiona sobre la importancia de la persistencia de datos, el diseño modular y la validación de entradas, sentando así las bases para el desarrollo de aplicaciones confiables, eficientes y centradas en el usuario. Esta clase representa el puente entre el aprendizaje técnico y su aplicación profesional.
-
16.1. Revisiones clave para el proyecto
El proyecto desarrollado a lo largo de las 16 clases ha sido diseñado para guiar al estudiante, paso a paso, en la construcción de una calculadora avanzada. Esta calculadora, lejos de ser un simple sumador, representa una herramienta modular, estructurada, escalable y profesional, desarrollada bajo los principios fundamentales de la programación.
A lo largo de este trayecto, se ha reforzado el enfoque por retos. Cada uno de los retos no solo representó un avance funcional, sino que también consolidó un conjunto específico de competencias relacionadas con los Resultados de Aprendizaje (RDA). Este enfoque promueve la progresividad, la comprensión profunda y la integración de conocimientos teóricos con habilidades prácticas.
Reto 1: Variables, Tipos de Datos y Operaciones BásicasEste primer reto marca el punto de partida en la construcción del proyecto, y está diseñado para familiarizar a los estudiantes con los fundamentos de la programación. En esta etapa inicial, los estudiantes trabajaron con variables, que son espacios en memoria donde se almacenan datos, y aprendieron cómo declarar, asignar y manipular su contenido. Se profundizó en los tipos de datos primitivos en Python, como int (enteros), float (decimales) y str (cadenas de texto), y se discutió cómo estos tipos determinan el comportamiento de las operaciones que se pueden realizar.
El foco principal estuvo en desarrollar la capacidad de realizar operaciones aritméticas básicas como suma, resta, multiplicación y división, entendiendo las reglas de precedencia y el uso correcto de operadores. A través de ejercicios prácticos, los estudiantes también comprendieron la diferencia entre entrada de datos (input()) y salida de datos (print()), lo cual les permitió construir programas interactivos simples.
Además, se introdujo el concepto de conversión de tipos (casting), indispensable cuando se requiere operar entre diferentes tipos de datos (por ejemplo, convertir una cadena a número para poder sumar). Esta etapa sienta las bases para la lógica computacional y el pensamiento algorítmico, elementos esenciales que se irán reforzando en los siguientes retos del proyecto.
Figura 1: Flujo básico de entrada, operación y salida Fuente: Creación de autor, D. Nicolalde. Figura 1: Flujo básico de entrada, operación y salida Fuente: Creación de autor, D. Nicolalde.
Reto 2: Control de Flujo y RepeticiónEn este segundo reto, los estudiantes profundizaron en el control de flujo del programa, aprendiendo a tomar decisiones basadas en condiciones mediante el uso de estructuras como if, elif y else. Estas herramientas permitieron que el programa no solo realice cálculos, sino que reaccione de forma inteligente ante diferentes entradas del usuario. Por ejemplo, si el usuario seleccionaba una operación no válida, el sistema podía mostrar un mensaje de advertencia o repetir la pregunta, mejorando la interacción con el sistema.
Otro componente clave de este reto fue la introducción y práctica intensiva de los bucles de repetición: while y for. Se enseñó a los estudiantes cómo usar estos bucles para repetir instrucciones múltiples veces, ya sea en función de un contador (for) o de una condición lógica (while). Esto habilitó la creación de menús interactivos, donde el usuario podía seleccionar varias operaciones sin tener que reiniciar el programa, lo cual representó un paso importante hacia la automatización y fluidez de la interfaz.
También se abordaron conceptos fundamentales como las expresiones booleanas, los operadores lógicos (and, or, not) y los errores comunes al diseñar condiciones. En conjunto, este reto fue esencial para ayudar a los estudiantes a comprender cómo se comportan los programas cuando enfrentan diferentes caminos posibles de ejecución, y cómo controlar esos caminos para crear programas más versátiles, robustos y adaptables.
Figura 2: Diagrama de flujo para selección de operación y bucle Fuente: Creación de autor, D. Nicolalde. Figura 2: Diagrama de flujo para selección de operación y bucle Fuente: Creación de autor, D. Nicolalde.
Descripción: Ilustra cómo el usuario elige una operación del menú y puede repetirla.
Reto 3: Funciones, Modularidad y ComplejidadEn este tercer reto, los estudiantes dieron un paso crucial hacia una programación más profesional mediante la introducción de funciones. Se promovió la práctica del principio de modularidad, que consiste en dividir un programa en partes más pequeñas y manejables llamadas funciones. Cada función fue diseñada para realizar una tarea específica, lo que permitió encapsular la lógica, reducir la repetición de código y mejorar significativamente la organización y claridad del programa.
Los estudiantes aprendieron a declarar funciones con parámetros de entrada, que permiten recibir información desde otros puntos del programa, y valores de retorno, que permiten enviar resultados de vuelta al bloque principal o a otras funciones. Esta dinámica fomentó una mayor comprensión sobre el flujo de datos entre funciones, así como sobre el diseño de interfaces claras entre los diferentes componentes del sistema.
A nivel técnico, este reto introdujo operaciones matemáticas más complejas, como el cálculo de potencias mediante el operador ** o la función pow(), y raíces cuadradas utilizando math.sqrt() o exponenciación fraccionaria. Además, se comenzaron a integrar estructuras más avanzadas como listas y matrices, permitiendo a los estudiantes trabajar con colecciones de datos para operaciones como suma de elementos, recorrido con bucles anidados y validaciones de estructuras.
Este reto también exigió aplicar los conocimientos de control de flujo aprendidos previamente, pero en el contexto de un sistema modular. Como resultado, los estudiantes desarrollaron calculadoras extendidas capaces de manejar múltiples operaciones, organizadas en funciones que podían ser llamadas desde un menú central. Así, el proyecto evolucionó de un sistema lineal a un sistema estructurado, reutilizable y escalable, sentando las bases para resolver problemas reales con mayor eficiencia y claridad.
Figura 3: Estructura modular del programa con funciones Fuente: Creación de autor, D. Nicolalde. Figura 3: Estructura modular del programa con funciones Fuente: Creación de autor, D. Nicolalde.
Descripción: Muestra cómo cada operación matemática se maneja mediante funciones independientes.
Reto 4: Persistencia con Archivos de Texto e Integración TotalEl cuarto y último reto representó el cierre integrador del proyecto, donde los estudiantes debían combinar todas las habilidades adquiridas en los retos anteriores para construir un sistema completo y funcional: una calculadora avanzada con capacidad de guardar y recuperar datos persistentes desde archivos de texto. Este reto fortaleció el pensamiento sistémico al permitir que los estudiantes reflexionen sobre cómo cada componente del programa se conecta y coopera con los demás.
La novedad central de este reto fue introducir el concepto de persistencia de información mediante archivos, utilizando funciones como open(), write() y read() en combinación con el uso seguro del contexto with. Los estudiantes aprendieron a almacenar los resultados de las operaciones en un archivo de historial (por ejemplo, historial.txt), y a implementar funciones para leer registros previos, facilitando la consulta, auditoría o reutilización de cálculos pasados.
Además, se reforzó el uso del manejo de excepciones (try-except) como una buena práctica para construir programas resilientes y seguros ante errores comunes, como archivos inexistentes o problemas de permisos. Esta práctica les permitió implementar mecanismos de recuperación de errores y mejorar la experiencia del usuario final.
Los estudiantes consolidaron su proyecto en una versión final integrada, que incluía todas las operaciones básicas y avanzadas, estructura modular mediante funciones, control de flujo completo, interacción con el usuario, y persistencia de datos. Este reto permitió evaluar no solo los conocimientos técnicos adquiridos, sino también habilidades transversales como la planificación, depuración, documentación y mejora continua del código.
Figura 4: Flujo de lectura y escritura de operaciones en archivo Fuente: Creación de autor, D. Nicolalde. Figura 4: Flujo de lectura y escritura de operaciones en archivo Fuente: Creación de autor, D. Nicolalde.<
Descripción: Muestra cómo se registran los resultados y se leen operaciones pasadas desde archivos.
La Tabla 1 resume las habilidades clave desarrolladas por los estudiantes en cada reto del proyecto de la calculadora. Muestra cómo, progresivamente, se dominaron conceptos desde la entrada de datos hasta el manejo de errores. Cada reto fortaleció componentes técnicos esenciales que culminan en una solución funcional e integrada.
Reto Habilidad Principal Componentes técnicos desarrollados 1 Entrada y operaciones básicas input(), print(), operadores aritméticos 2 Control del flujo if, while, menú interactivo 3 Modularidad y funciones def, llamadas con argumentos, retorno 4 Persistencia de datos y robustez Archivos de texto, excepciones, integración total Tabla 1: Resumen de habilidades adquiridas por reto Reto 1Habilidad Principal: Entrada y operaciones básicas
Componentes: input(), print(), operadores aritméticos
Reto 2Habilidad Principal: Control del flujo
Componentes: if, while, menú interactivo
Reto 3Habilidad Principal: Modularidad y funciones
Componentes: def, llamadas con argumentos, retorno
Reto 4Habilidad Principal: Persistencia de datos y robustez
Componentes: Archivos de texto, excepciones, integración total
Figura 5: Diagrama de interacción completa del proyecto Fuente: Creación de autor, D. Nicolalde. Figura 5: Diagrama de interacción completa del proyecto Fuente: Creación de autor, D. Nicolalde.
Descripción: Resume cómo cada módulo (entrada, menú, funciones, archivo) se conecta al sistema.
-
16.2 Tipos de pruebas¿Qué son las pruebas de software?
Las pruebas de software son una actividad sistemática dentro del ciclo de vida del desarrollo de software que tiene como finalidad evaluar y verificar que un programa o sistema informático funcione correctamente de acuerdo con los requisitos especificados. Desde una perspectiva teórica, las pruebas representan un proceso de validación y verificación cuyo objetivo principal es identificar errores, fallos o desviaciones en el comportamiento del software, antes de su implementación definitiva o liberación al usuario final.
Más allá de simplemente encontrar errores, las pruebas buscan aumentar la confianza en el producto desarrollado. Esto se logra evaluando su comportamiento en distintos escenarios y asegurando que cumple con lo esperado bajo condiciones normales, límite y anómalas. En términos académicos, se considera que el proceso de pruebas es un elemento clave en la garantía de calidad del software, ya que permite asegurar que el producto sea confiable, eficiente, seguro y utilizable.
Importancia dentro del ciclo de desarrollo de softwareEn el marco del ciclo de vida del software, las pruebas actúan como un filtro de calidad que ayuda a:
- Validar que el software cumple con los requerimientos funcionales y no funcionales establecidos desde la etapa de análisis.
- Verificar que los módulos y componentes trabajen correctamente de forma aislada y en conjunto.
- Reducir los riesgos asociados a fallos en producción o fallos catastróficos en sistemas críticos.
- Optimizar el tiempo y costo de mantenimiento a largo plazo, al detectar errores en etapas tempranas.
Las pruebas no se limitan a una sola fase: están presentes desde el diseño (con pruebas de verificación tempranas), durante la codificación (pruebas estructurales) y al finalizar (pruebas de aceptación), formando así un proceso transversal e iterativo.
Realizar pruebas adecuadas es fundamental para asegurar que el sistema cumple con los requisitos y se comporta correctamente incluso en condiciones adversas. A continuación, se presentan los tipos de pruebas que los estudiantes deben aplicar al finalizar su proyecto.
16.2.1. Pruebas Unitarias
Las pruebas unitarias son una metodología fundamental en el desarrollo de software que consiste en verificar cada componente del programa de forma aislada, generalmente una función a la vez. El objetivo principal es comprobar que cada función individual realiza correctamente su tarea, sin depender de otras partes del sistema.
Este tipo de prueba ayuda a:
- Detectar errores rápidamente en etapas tempranas del desarrollo.
- Facilitar la depuración y el mantenimiento del código.
- Asegurar que los cambios en una parte del código no afecten otras funcionalidades.
Ejemplos:- Probar sumar(a, b) con diferentes combinaciones (positivos, negativos, cero).
- Probar potencia(base, exponente) y validar que funcione con valores grandes y pequeños.
- Comprobar que la función guardar_resultados() escriba el archivo en el formato correcto.
Aprende más
El video titulado explica de forma clara y didáctica el concepto de pruebas unitarias en programación. ¡Accede aquí!
16.2.2. Pruebas de Integración
Las pruebas de integración se centran en verificar cómo funcionan juntas varias partes del programa, es decir, la interacción entre los distintos módulos o funciones. Aunque cada componente individual (como sumar() o leer_archivo()) puede funcionar correctamente de forma aislada, los errores pueden surgir al conectarlos.
Este tipo de pruebas busca responder preguntas como:
- ¿Se están transfiriendo correctamente los datos entre funciones?
- ¿La salida de una función sirve como entrada adecuada para otra?
- ¿Se mantienen los resultados esperados cuando el flujo pasa por varios componentes del sistema?
Importancia de las pruebas de integración:
- Detectan fallos en la comunicación entre módulos que las pruebas unitarias no pueden encontrar.
- Aseguran que el programa completo funcione de forma fluida y coherente.
- Permiten simular escenarios reales de uso, como un usuario utilizando el sistema de principio a fin.
Ejemplos:- Leer datos desde el archivo, procesarlos con funciones y luego escribir los resultados.
- Ejecutar una operación, guardar el resultado, cerrar el programa, reabrirlo y continuar desde donde se quedó.
16.2.3. Pruebas de Manejo de Errores (Robustez)
Las pruebas de manejo de errores, también llamadas pruebas de robustez, se centran en evaluar si el programa responde de forma segura y controlada ante errores comunes. En lugar de permitir que el programa se bloquee o arroje un mensaje técnico incomprensible, estas pruebas buscan que el sistema:
- Evite fallos inesperados.
- Capture excepciones y las maneje apropiadamente.
- Informe al usuario con mensajes claros, amigables y útiles.
Estas pruebas son fundamentales para garantizar que la aplicación sea confiable en situaciones reales, especialmente cuando el usuario comete errores o el entorno presenta condiciones adversas (archivos dañados, entradas incorrectas, etc.).
Ejemplos:- Dividir por cero.
- Ingresar texto cuando se espera un número.
- Abrir un archivo inexistente.
16.2.4. Pruebas de Usabilidad
Las pruebas de usabilidad no se enfocan en encontrar errores técnicos, sino en evaluar la experiencia del usuario al interactuar con el programa. Su objetivo es asegurar que el sistema sea intuitivo, fácil de usar y agradable, incluso para personas sin experiencia técnica. Estas pruebas son clave para mejorar la accesibilidad y claridad del software.
Un programa puede ser técnicamente correcto pero frustrante de usar. Las pruebas de usabilidad permiten detectar elementos confusos, redundantes o poco claros, y guiar mejoras que hacen que el usuario comprenda y utilice el sistema sin esfuerzo ni frustración.
Ejemplos:- Verificar que los menús sean claros y las opciones estén bien organizadas.
- Comprobar que los mensajes de error guíen al usuario.
- Medir si el flujo del programa es comprensible sin instrucciones externas.
16.2.5. Verificación y Pruebas Finales
Antes de declarar el proyecto como finalizado, se enfatizó la importancia de realizar pruebas. Este proceso implica alimentar al sistema con distintos tipos de entrada y validar los resultados esperados. Se explicó también cómo capturar errores y comportamientos inesperados.
Figura 6: Flujo de validación de entradas y manejo de excepciones Fuente: Creación de autor, D. Nicolalde. Figura 6: Flujo de validación de entradas y manejo de excepciones Fuente: Creación de autor, D. Nicolalde.
Descripción: Representa cómo se interceptan errores comunes antes de causar fallos graves.
La Tabla 2 presenta los tipos de pruebas esenciales recomendadas para garantizar la calidad del proyecto final. Cada tipo aborda un aspecto diferente: desde la validación de funciones individuales hasta la interacción entre módulos, el manejo de errores y la experiencia del usuario. Esta clasificación ayuda a estructurar una verificación integral del sistema desarrollado.
Tipo de prueba Objetivo Ejemplo en el proyecto Prueba unitaria Validar que una función individual funcione Validar que multiplicar(3, 4) retorne 12; o que calcular_raiz(9) retorne 3.0 Prueba de integración Comprobar que los módulos trabajan juntos Ejecutar una operación, guardar el resultado, cargarlo nuevamente y continuar la operación Prueba de errores Evaluar el manejo de errores comunes Intentar dividir por cero, ingresar texto donde se espera un número, o abrir un archivo inexistente Pruebas de Usabilidad Evalúan la claridad de menús, mensajes, y flujo lógico del sistema Confirmar que el menú guía correctamente al usuario y que los mensajes de error son comprensibles Tabla 2: Tipos de pruebas recomendadas Prueba unitariaObjetivo: Validar que una función individual funcione
Ejemplo: Validar que multiplicar(3, 4) retorne 12; o que calcular_raiz(9) retorne 3.0Prueba de integraciónObjetivo: Comprobar que los módulos trabajan juntos
Ejemplo: Ejecutar una operación, guardar el resultado, cargarlo nuevamente y continuar la operaciónPrueba de erroresObjetivo: Evaluar el manejo de errores comunes
Ejemplo: Intentar dividir por cero, ingresar texto donde se espera un número, o abrir un archivo inexistentePruebas de UsabilidadObjetivo: Evaluar la claridad de menús, mensajes y flujo lógico del sistema
Ejemplo: Confirmar que el menú guía correctamente al usuario y que los mensajes de error son comprensibles
Aprende más
El video ofrece una guía completa para principiantes sobre cómo implementar pruebas en Python ¡Accede aquí!
Profundiza más
Este recurso te ayudará a enfatizar sobre el tema ¡Accede aquí!
-
-
-
Actividades
-
Hacer intentos: 1
-
Hacer intentos: 1
-
Proyecto final y archivos de texto
-
Hacer intentos: 1
-
Hacer intentos: 1