Fundamentos de Programación
En un mundo que ha sufrido un importante proceso de transformación digital cada vez hay más aplicativos desarrollados con el fin de interactuar con los seres humanos, si estos aplicativos no están correctamente programados un atacante puede hacer uso mal intencionado del software y controlar el flujo de ejecución, pudiendo alterar la información y/o robarla.
Antes de nada, haremos una distinción fundamental entre hardware y software
- Hardware: Todos los componentes físicos de un ordenador.
- Software: Programas e instrucciones para ejecutar tareas en un ordenador.
Una vez tenemos claro la diferencia, en esta entrada de este blog nos centraremos en el software, y en una de sus unidades fundamentales: Los Programas.
Definiríamos programa como:
- Secuencia de instrucciones.
- Entendible por el ordenador.
- Tienen un objetivo o tarea concreta.
Los ordenadores son máquinas eléctricas que sólo entienden de 0 y 1, siendo:
- 0 no hay corriente (0.3 voltios).
- 1 hay corriente (0.5 voltios).
Este es el único lenguaje que entiende el ordenador, llamado lenguaje binario.
Un programa es un conjunto de instrucciones que se crea para realizar una tarea específica en una computadora. Estas instrucciones son escritas en un lenguaje de programación y se traducen a un lenguaje que la computadora puede entender y ejecutar. Los programas pueden ser simples, como una calculadora, o muy complejos, como un sistema operativo. En esencia, un programa es como una receta que le dice a la computadora qué hacer y cómo hacerlo. Los programadores crean programas para automatizar tareas, procesar datos, resolver problemas y realizar una amplia variedad de funciones en la computadora.
Como ya hemos dicho para crear un programa y que la computadora lo interprete y ejecute, las instrucciones deben escribirse en un lenguaje de programación. En los primeros tiempos de la computación se programaba directamente en código máquina. Escribir programas así resultaba demasiado complicado, también era difícil entenderlos y mantenerlos una vez escritos. Con el tiempo, se fueron desarrollando herramientas para facilitar el trabajo y aparecieron los lenguajes de programación, que podemos dividir en dos grupos:
- Lenguajes de bajo nivel: son los más cercanos al binario, pero son difíciles de programar.
- Lenguajes de alto nivel: necesitan ser traducidos antes de llegar al ordenador, pero son fáciles de programar ya que son más cercanos al lenguaje natural de las personas
Algunos ejemplos:
- Lenguajes bajo nivel: lenguaje máquina y Ensamblador.
- Lenguajes alto nivel: C, C++, Java, PHP, Python, Go, Rust, Ruby...
En el desarrollo de software hay muchas condicionantes que marcan que elección de lenguaje se usará en el proyecto:
- Requisitos técnicos marcados por otras piezas de software/hardware.
- Tiempo de entrega del software.
- Necesidad de rendimiento.
Programar viene a ser el proceso de crear un software fiable mediante la escritura en un lenguaje (code en inglés), prueba (test), depuración (debug), compilación o interpretación, y mantenimiento (maintenance) del código fuente de dicho programa informático.
CODIFICAR ⇒ PROBAR ⇒ DEPURAR ⇒ COMPILAR/INTERPRETAR ⇒ MANTENER (y vuelta a empezar)
El funcionamiento de un equipo informático es relativamente sencillo. En un área de la memoria principal se tiene un conjunto de bits agrupados en unidades denominadas instrucciones, que son potencias de 2 y cuyo tamaño depende de la arquitectura del equipo: 8 bits, 16 bits, 32 bits, 64 bits, 128 bits. El procesador obtiene la siguiente instrucción a ejecutar, la interpreta y manda "órdenes" a los diferentes elementos del equipo como registros, memoria principal, ALU o periféricos, una vez finalizada la instrucción pasa a la siguiente instrucción de la memoria principal.
- JavaScript: es el lenguaje más demandado actualmente. Desde su origen como herramienta para crear sitios web dinámicos, ha evolucionado hacia un ecosistema completo para el desarrollo frontend y backend. Entornos como Node.js y herramientas como Electron han extendido su uso a aplicaciones móviles y de escritorio. Con la aparición de TypeScript, que añade tipado estático a JavaScript, se ha reforzado su uso en grandes proyectos empresariales y frameworks como Angular o NestJS. Su presencia en el mercado laboral supera el 31% de las ofertas. Además, su formato de intercambio de datos, JSON, se ha consolidado como estándar en APIs y comunicación entre servicios.
- Python: destaca por su sintaxis clara y su enorme versatilidad. Se utiliza intensamente en campos como inteligencia artificial, ciencia de datos, desarrollo web, automatización de tareas y scripting. Librerías como TensorFlow, Keras, Pandas o NumPy han posicionado a Python como el lenguaje de referencia en proyectos de análisis de datos y machine learning. Su uso en desarrollo web también es notable gracias a frameworks como Django y Flask, ideales para crear aplicaciones escalables. Python representa aproximadamente el 20% de las ofertas laborales y es uno de los lenguajes con mayor crecimiento en sectores como el financiero, el académico o el tecnológico.
- Java: mantiene su lugar como lenguaje de referencia en entornos corporativos. Su robustez, portabilidad y madurez lo hacen ideal para desarrollar aplicaciones empresariales, sistemas distribuidos y software Android. Frameworks como Spring lo mantienen en el centro del desarrollo backend a gran escala. Java sigue siendo fundamental en sectores críticos como la banca, seguros, telecomunicaciones y servicios públicos. A pesar del ascenso de alternativas como Kotlin, Java ocupa el 18% de las ofertas de empleo, lo que lo consolida como uno de los lenguajes más estables del mercado.
- C#: desarrollado por Microsoft, se emplea ampliamente en el entorno .NET para crear aplicaciones de escritorio, web y móviles. Es especialmente fuerte en el mundo de los videojuegos gracias a Unity, y en el desarrollo multiplataforma mediante Xamarin. En la actualidad, C# también ha ganado terreno en desarrollo web moderno con tecnologías como Blazor, que permite crear interfaces interactivas con C# en el navegador. Su flexibilidad y rendimiento lo convierten en una herramienta muy utilizada en empresas tecnológicas y estudios de videojuegos. C# representa alrededor del 12% de las ofertas laborales.
- PHP: sigue siendo uno de los lenguajes más utilizados en el desarrollo web del lado del servidor. Es la base de plataformas como WordPress, y se usa con frecuencia junto a frameworks como Laravel, que proporciona una arquitectura moderna y escalable. PHP es común en aplicaciones de comercio electrónico, como Magento o WooCommerce, y sigue siendo una opción accesible para desarrolladores por su baja barrera de entrada. A pesar de las críticas a su diseño, sigue representando un 10% del mercado laboral, especialmente en pequeñas y medianas empresas.
- C y C++: son lenguajes esenciales para el desarrollo de software de bajo nivel, donde el control sobre la memoria y el hardware es crítico. C es ampliamente utilizado en sistemas embebidos y desarrollo de sistemas operativos, mientras que C++, con sus capacidades orientadas a objetos, se emplea en videojuegos (Unreal Engine), simulaciones científicas, sistemas bancarios y control de infraestructuras críticas. Aunque su demanda ha descendido ligeramente, C/C++ todavía representa un 6–7% del mercado, especialmente en entornos que requieren máxima eficiencia.
- Ruby: es conocido por su enfoque en la simplicidad y la productividad, siendo especialmente popular en el desarrollo web gracias a Ruby on Rails. Este framework ha sido clave en el crecimiento de muchas startups por su rapidez para lanzar productos al mercado. Empresas como GitHub, Shopify o Basecamp han apostado por Ruby en sus orígenes. Aunque su presencia es menor que la de otros lenguajes, sigue representando alrededor del 4% de las ofertas laborales, con una comunidad activa y leal.
- Go (Golang): desarrollado por Google, ha ganado relevancia por su eficiencia y rendimiento en sistemas concurrentes. Es muy utilizado en servicios web, microservicios y plataformas en la nube, por su capacidad para gestionar múltiples procesos de forma eficiente. Go es empleado en empresas como Uber, Dropbox o Netflix. Su diseño simple y sus herramientas integradas lo hacen ideal para backend moderno. Aunque su cuota de mercado es más baja (2%), su adopción sigue creciendo en entornos de infraestructura y alto rendimiento.
- Bash/Shell: no es un lenguaje de propósito general, pero es fundamental en sistemas Unix/Linux para la automatización de tareas administrativas, la gestión de servidores y la creación de scripts de despliegue. Es indispensable en entornos DevOps, administración de redes y CI/CD. Aunque no aparece entre los lenguajes principales en desarrollo de aplicaciones, su dominio es obligatorio para perfiles de infraestructura.
- Rust
- Kotlin
- Lua
- Dart
- Assembly
- Swift
- R
- Go
- Visual Basic (.Net)
- MATLAB
- Scratch
- Carácter (char): Representa un único símbolo, como letras, dígitos o signos de puntuación. Internamente, cada carácter se codifica mediante estándares como ASCII (7 bits) o Unicode, este último necesario para soportar múltiples idiomas y conjuntos de símbolos ampliados. Además de caracteres visibles, también incluye caracteres de control como el salto de línea o el tabulador, usados para gestionar el formato del texto.
- Entero (int): Almacena números enteros sin decimales. El rango de valores depende del número de bits utilizados: por ejemplo, un entero de 8 bits puede representar de 0 a 255 (sin signo) o de -128 a 127 (con signo). Los enteros son esenciales en cálculos discretos,estructuras indexadas (como arrays) y en programación de bajo nivel. Los lenguajes suelen diferenciar entre enteros con signo y sin signo, lo que afecta tanto al rango como al comportamiento de las operaciones.
- Real o coma flotante (float, double): Representa números reales con decimales, útiles en cálculos matemáticos y científicos. Se basan en el estándar IEEE 754, y suelen diferenciarse en:
- Precisión simple (32 bits): Ahorra memoria, con menor precisión decimal.
- Precisión doble (64 bits): Ofrece mayor precisión, a costa de más uso de memoria. Son indispensables en simulaciones, visualización gráfica y procesamiento numérico, aunque deben manejarse con cuidado debido a problemas de redondeo o pérdida de precisión.
- Booleano (bool): Solo puede tomar dos valores: verdadero (true) o falso (false). Este tipo es fundamental en estructuras de control como if, while o for, y se basa en lógica binaria. Permite evaluar condiciones y tomar decisiones mediante operadores lógicos como AND (&&), OR (||) y NOT (!). Su uso está muy extendido en validaciones, algoritmos condicionales y estructuras de decisión.
- Cadena de caracteres (string): Es una secuencia ordenada de caracteres, normalmente almacenada como un array de char. Las cadenas permiten operaciones como concatenación, búsqueda de patrones, extracción de subcadenas, y son claves en aplicaciones de entrada/salida de texto, bases de datos o comunicación en red. En la mayoría de lenguajes, los strings se manejan como objetos o tipos de datos especiales, con métodos específicos para su manipulación.
- Puntero (pointer): Almacena una dirección de memoria, es decir, apunta al lugar donde se encuentra almacenado otro dato. El uso de punteros permite acceso directo y eficiente a estructuras dinámicas, como listas enlazadas o árboles binarios. También se emplean para invocar funciones, gestionar memoria dinámica o construir interfaces entre módulos. Sin embargo, su uso indebido puede provocar fallos graves de seguridad o errores de ejecución, como accesos inválidos o fugas de memoria, motivo por el cual muchos lenguajes modernos restringen o controlan su uso mediante técnicas de verificación de tipos o manejo seguro de referencias.
- Aritméticos: Los operadores aritméticos son fundamentales en cualquier lenguaje de programación y se utilizan para realizar cálculos básicos entre los tipos de datos numéricos. Entre las operaciones más comunes se encuentran la suma, resta, multiplicación, división y módulo. Algunos lenguajes también permiten utilizar ciertos operadores aritméticos para trabajar con cadenas de caracteres, como la concatenación.
- Unarios: Los operadores unarios son aquellos que actúan sobre un único operando y realizan operaciones específicas como incremento, decremento o negación. Aunque no están presentes en todos los lenguajes de programación, son fundamentales en aquellos que los implementan, como C, C++, Java y JavaScript. A continuación, se muestran dos operadores unarios comunes:
- Relacionales: Los operadores relacionales son símbolos que se usan para comparar dos valores. Si el resultado de la comparación es correcto, la expresión se considera verdadera; en caso contrario, es falsa.
- Lógicos: Los operadores lógicos son utilizados en lenguajes de programación para combinar expresiones. Los más comunes son:
- AND (&&): El resultado es verdadero si ambas expresiones son verdaderas.
- OR (||): El resultado es verdadero si alguna de las expresiones es verdadera.
- NOT (!): El resultado invierte la condición de la expresión.
- Operador NAND: En el operador NAND, cuando las dos entradas son altas, la salida será baja. Es la negación del operador AND.
- Operador NOR: En el operador NOR, cuando ambas entradas están en estado bajo, la salida será alta. Es la negación del operador OR.
- Operador XOR: En el operador XOR, la salida será baja cuando ambas entradas estén en el mismo estado (bajo o alto). La salida será alta cuando las entradas sean diferentes.
- Operador XNOR: En el operador XNOR, la salida será baja cuando una de las dos entradas esté en estado alto. Es la negación del operador XOR.
- If-else: Se indica una condición que al evaluarse devuelve cierto o falso y en función del resultado ejecuta uno u otro bloque.
- Switch: Permite evaluar una expresión y ejecutar más de dos posibles opciones en función de la expresión. Dependiendo del lenguaje, la expresión se puede limitar a comparar números enteros o caracteres como en C o en lenguajes más recientes como C# con enteros, caracteres, cadenas, booleanos o enumerados.
- While: Se ejecuta el bloque contenido en la estructura mientras se cumpla la condición lógica. Se puede dar el caso de no ejecutarse ninguna vez.
- Do-While: Se ejecuta el bloque contenido en la estructura mientras se cumpla la condición lógica. La evaluación de la condición se ejecuta al final del bloque de instrucciones.
- For: En este caso, además de la condición, posee un bloque de instrucciones que se ejecutan al inicio, el bloque en el que se encuentra la condición a evaluar en cada iteración y por último un bloque de instrucciones que se ejecuta en cada iteración del bucle. Si bien es posible indicar varias instrucciones separadas por comas en cada elemento del bucle for, no suele ser usual utilizarlo ya que no es intuitivo...
- Por valor: Se realiza una copia de la variable y esta copia es la que recibe la función, por tanto los cambios realizados en función no tienen consecuencias en la variable original.
- Por referencia: Ya sea con los mecanismos que provee de C (dirección de memoria del inicio de la variable que se pasa como argumento, conocida como puntero), Java (en las variable original se almacenan la dirección del objeto y se realiza una copia de la variable a pasar corno argumento, referenciando la copia también al objeto) o de otros lenguajes, las consecuencia principal es que las modificaciones realizadas dentro de la función afectan a la variable pasada como argumento.
- Encapsulación: Cada objeto protege sus datos internos, exponiendo solo lo necesario a través de una interfaz definida. Esto favorece la seguridad y la modularidad del código, al evitar dependencias innecesarias entre componentes.
- Abstracción: Los objetos modelan conceptos del sistema, ocultando la complejidad interna y mostrando solo lo relevante para el uso externo. Este principio permite centrarse en lo esencial y reducir el acoplamiento.
- Herencia: Permite crear nuevas clases basadas en clases existentes, reutilizando código y favoreciendo la organización jerárquica de conceptos. Las subclases heredan atributos y métodos de sus superclases, pudiendo extender o modificar su comportamiento.
- Polimorfismo: Los objetos pueden responder de manera diferente a una misma operación, dependiendo de su tipo o contexto. Esto se traduce en la posibilidad de usar interfaces comunes con implementaciones diversas, facilitando la extensibilidad del sistema.
- Librerías estáticas: Se integran directamente en el archivo ejecutable del programa durante el proceso de compilación. Esto significa que, una vez compilado, el programa no necesita la librería por separado para funcionar, pero aumenta el tamaño del ejecutable.
- Librerías dinámicas (o compartidas): Estas se cargan durante la ejecución del programa, permitiendo que varios programas utilicen la misma librería sin necesidad de duplicarla en cada uno. Ejemplos comunes incluyen DLLs (Dynamic Link Libraries) en Windows o .so (Shared Objects) en sistemas Unix/Linux.
- Reutilización del código: Evita la duplicación de esfuerzos y mejora la eficiencia del desarrollo.
- Facilidad de mantenimiento: Las actualizaciones o correcciones en una librería pueden beneficiar a todos los programas que la utilizan.
- Reducción de errores: Al utilizar código probado y validado, se minimizan los riesgos de fallos.
- Abstracción: Permite al desarrollador utilizar funcionalidades complejas sin necesidad de entender los detalles internos de su implementación
- Lenguaje compilado
- Nuestro código fuente se transforma en un binario mediante compilación.
- El ordenador ejecuta el binario.
- No necesitamos por tanto ningún programa adicional.
- Lenguaje interpretado
- Nuestro código fuente es leído en tiempo real por un programa (intérprete) que lo traduce a código máquina (objeto binario).
- El ordenador ejecuta ese binario.
- Necesita por tanto un programa adicional, llamado intérprete, que hace de traductor entre las instrucciones y el código máquina.
- Lenguaje intermedio
- El código fuente se compila a un lenguaje intermedio.
- Este lenguaje intermedio se ejecuta en una máquina virtual.
- Un intérprete traduce el código fuente linea a línea como se describe a continuación: primero traduce la primera línea, detiene la traducción y, seguidamente la ejecuta; lee la siguiente línea, detiene la traducción y la ejecuta, y así sucesivamente. El intérprete tiene que estar cargado en memoria ejecutándose para poder ejecutar el programa. Al igual que el intérprete, el código fuente tiene que estar también en la memoria. En caso de detectar un error durante el proceso de traducción el intérprete detiene la ejecución del programa.
- PHP.
- Perl.
- Python.
- Ruby.
- Un compilador traduce un programa entero de un lenguaje de programación (llamado código fuente) a otro denominado lenguaje objetivo. Usualmente, el lenguaje objetivo es código máquina, aunque también puede ser traducido a un código intermedio (bytecode) o a texto. El compilador únicamente estará instalado en la máquina de desarrollo. El código generado para un sistema sólo funcionará para una arquitectura hardware y software determinadas. Si se desea ejecutar en un sistema con un hardware o software diferente habrá que volver a recompilarlo. Ejemplos de lenguajes compilados típicos son:
- C/C++.
- Pascal.
- Entre otros.
- Se compila una vez; se ejecuta muchas veces.
- La ejecución del programa objeto es mucho más rápida que si se interpreta el programa fuente.
- El compilador tiene una visión global del programa, por lo que la información de los mensajes de error es más detallada.
- Un intérprete necesita menos memoria que un compilador.
- Permite una mayor interactividad con el código en tiempo de desarrollo (e incluso, en algunos casos, mientras se ejecuta el código).
- Editor de Código: Los IDEs incluyen editores de código que ofrecen resaltado de sintaxis, sugerencias de autocompletado y otras características para mejorar la eficiencia de escritura.
- Depuración: Los entornos de desarrollo proporcionan herramientas de depuración que permiten a los programadores detectar y corregir errores en su código de manera eficiente.
- Gestión de Proyectos: Los IDEs suelen ofrecer funciones para organizar proyectos, gestionar bibliotecas y dependencias, y facilitar la colaboración en equipo.
- Integración con Herramientas: Pueden integrar herramientas de control de versiones, compiladores, analizadores estáticos y otros recursos que hacen que el desarrollo sea más efectivo.
- Personalización: Los entornos de desarrollo suelen ser altamente personalizables para adaptarse a las preferencias del programador.
- Soporte Multiplataforma: Muchos IDEs se pueden utilizar en sistemas operativos como Windows, macOS y Linux.
- Pruebas manuales
- Pruebas automáticas
- Pruebas de caja blanca: los evaluadores tienen acceso completo al código fuente y conocimiento detallado de la arquitectura del sistema.
- Pruebas de caja gris: los evaluadores tienen un conocimiento parcial del código fuente y la arquitectura del sistema. Combinan elementos de pruebas de caja blanca y caja negra.
- Pruebas de caja negra: no se tiene acceso al código, los evaluadores no tienen conocimiento del código fuente subyacente, solo interactúan con la aplicación desde una perspectiva de usuario externo.
- Examen de la unidad o pruebas unitarias: valida que cada unidad de software funcione como se esperaba. Una unidad es el componente comprobable más pequeño de una aplicación. Normalmente, la unidad más pequeña suele ser una función o método. Se realizan típicamente por desarrolladores durante el proceso de desarrollo.
- Pruebas de integración: verifican que distintos módulos que funcionan por separado funcionen de manera conjunta. Pueden ser pruebas de integración horizontal (pruebas entre componentes similares) o pruebas de integración vertical (pruebas entre capas de la aplicación).
- Pruebas funcionales: se centran en verificar si el software cumple con sus especificaciones funcionales. Evalúan las funciones (no confundir con las pruebas unitarias) y características del software para garantizar que funcionen como se espera.
- Pruebas de aceptación: verifican si todo el conjunto de software se comporta según lo esperado. Pueden ser pruebas de aceptación del usuario (UAT) realizadas por el cliente o pruebas de aceptación del negocio (BAT) realizadas por los analistas de negocio.
- Pruebas de usabilidad: estas pruebas confirman la eficacia y facilidad con la que un usuario puede interactuar con un sistema o una aplicación web para llevar a cabo una tarea específica. Ayudan a garantizar que el software sea intuitivo y satisfaga las necesidades del usuario.
- Pruebas de rendimiento: prueban el rendimiento del software con diferentes cargas de trabajo. Se utilizan para evaluar el rendimiento en condiciones de carga reales.
- Pruebas de regresión: verifican si el código introducido rompe o degrada la funcionalidad del software original. Suelen realizarse cuando hacemos cambios en un programa.
- Pruebas de Seguridad: estas pruebas evalúan la robustez del sistema ante posibles amenazas y vulnerabilidades. Garantizan que el software sea resistente a posibles ataques y cumpla con los estándares de seguridad.
- Pruebas de Análisis Estático (Static Analysis Testing): Analizan el código fuente o binario de una aplicación en busca de vulnerabilidades potenciales sin ejecutar el programa. Identifican problemas de seguridad a nivel de código y los IDEs suelen incluir extensiones para realizar dichas pruebas mientras los desarrolladores crean el código. Ejemplo de herramientas: Checkmarx, Fortify, SonarQube.
- Pruebas de Análisis Dinámico (Dynamic Analysis Testing): Evalúan el software en tiempo de ejecución para detectar posibles amenazas y vulnerabilidades mientras interactúa con el sistema. Ejemplo de herramientas: AppScan, Veracode, Burp Suite.
- Pruebas de Penetración (Penetration Testing): También conocidas como "pen tests", implican simular ataques controlados por parte de expertos en seguridad. El objetivo es identificar vulnerabilidades y puntos de entrada para posibles atacantes. Estas pruebas se realizan antes de poner en producción el software y periódicamente en el entorno de producción. Ejemplo de herramientas: Metasploit, Nmap, Burp Suite, OWASP ZAP.
- Pruebas de Vulnerabilidad (Vulnerability Assessment): Identifican y evalúan vulnerabilidades conocidas en sistemas y aplicaciones. Utilizan escáneres automatizados o herramientas especializadas para detectar debilidades de seguridad. Proporcionan una lista de vulnerabilidades que necesitan ser corregidas. Ejemplo de herramientas: Nessus, OpenVAS, Qualys, Nikto.
- Pruebas de Seguridad Web (Web Application Security Testing): Centradas en evaluar la seguridad de aplicaciones web y sitios web. Incluyen pruebas de inyección SQL, cross-site scripting (XSS), cross-site request forgery (CSRF), y otras vulnerabilidades específicas de la web. Ayudan a garantizar que las aplicaciones web sean resistentes a ataques comunes. Ejemplo de herramientas: OWASP ZAP, Burp Suite, Acunetix.
- Pruebas de Seguridad de Aplicaciones Móviles (Mobile Application Security Testing): Se enfocan en evaluar aplicaciones móviles en busca de vulnerabilidades específicas de plataformas móviles. Verifican la seguridad en aspectos como el almacenamiento de datos, la autenticación, y la comunicación segura. Ejemplo de herramientas: MobSF, OWASP Mobile Security Testing Guide, Burp Suite.
- Pruebas de Seguridad de Red (Network Security Testing): Evalúan la seguridad de la infraestructura de red, como firewalls, routers y conmutadores. Buscan posibles puntos débiles y vulnerabilidades en la red que podrían ser explotados. Ejemplo de herramientas: Wireshark, Nmap, Snort.
- Pruebas de Autenticación y Autorización: Evalúan la autenticación y autorización de usuarios y sistemas en una aplicación o red. Aseguran que solo los usuarios autorizados tengan acceso a recursos específicos. Estas pruebas no se basan en herramientas específicas, sino en casos de prueba diseñados para evaluar estas funciones.
- Pruebas de Seguridad de APIs (API Security Testing): Se centran en evaluar la seguridad de las interfaces de programación de aplicaciones (APIs) utilizadas para la comunicación entre sistemas. Verifican que las API sean seguras y resistentes a ataques. Ejemplo de herramientas: Postman, Swagger Inspector y OWASP API Security Top Ten.
- Pruebas de Estrés y Carga (Stress and Load Testing): Evalúan cómo el sistema se comporta bajo cargas de trabajo intensas o condiciones de estrés. Identifican cuellos de botella y problemas de rendimiento que podrían afectar la seguridad. Ejemplo de herramientas: Apache JMeter, LoadRunner y Gatling.
- Cada caso de prueba debe definir el resultado de salida esperado.
- El programador debe evitar probar sus propios programas, ya que desea (consciente o inconscientemente) demostrar que funcionan sin problemas.
- Se debe inspeccionar a conciencia el resultado de cada prueba, y así, poder descubrir posibles síntomas de defectos.
- Al generar casos de prueba, se deben incluir tanto datos de entrada válidos y esperados como no válidos e inesperados.
- Las pruebas deben centrarse en dos objetivos (es habitual olvidar el segundo):
- Probar que el programa hace lo que debe hacer.
- Probar que el programa no hace lo que no debe hacer.
- Todos los casos de prueba deben documentarse y diseñarse con cuidado.



