Soy un desarrollador de software relativamente nuevo, y una de las cosas que creo que debería mejorar es mi capacidad de probar mi propio código. Cada vez que desarrollo una nueva funcionalidad, me resulta muy difícil seguir todos los caminos posibles para poder encontrar errores. Tiendo a seguir el camino donde todo funciona. Sé que este es un problema bien conocido que tienen los programadores, pero no tenemos evaluadores en mi empleador actual y mis colegas parecen ser bastante buenos en esto.
En mi organización, no realizamos ni pruebas de desarrollo ni pruebas unitarias. Me ayudaría mucho, pero no es probable que esto cambie.
¿Qué creen que podría hacer para superar esto? ¿Qué enfoque utilizas cuando pruebas tu propio código?
Respuestas:
El trabajo de un codificador es construir cosas.
El trabajo de un probador es romper cosas.
Lo más difícil es romper cosas que acabas de construir. Solo tendrá éxito al superar esta barrera psicológica.
fuente
Franciso, voy a hacer algunas suposiciones aquí, en base a lo que has dicho:
"No hacemos ni TDD ni pruebas unitarias. Me ayudaría mucho, pero no es probable que esto cambie".
A partir de esto, sospecho que su equipo no le da mucho valor a las pruebas o la administración no le dedicará tiempo al equipo para tratar de ordenar el código existente y mantener la deuda técnica al mínimo.
En primer lugar, debe convencer a su equipo / administración del valor de las pruebas. Sé diplomático Si la administración mantiene a su equipo avanzando, debe mostrarle algunos datos, como la tasa de defectos para cada versión. El tiempo dedicado a reparar defectos podría dedicarse mejor a otras cosas, como mejorar la aplicación y hacer que se adapte mejor a los requisitos futuros.
Si el equipo y la gerencia en general son apáticos acerca de arreglar el código y usted no está contento con él, es posible que deba buscar otro lugar para trabajar, a menos que pueda convencerlos como ya he dicho. He encontrado este problema en diferentes grados en todos los lugares donde he trabajado. Podría ser cualquier cosa, desde la falta de un modelo de dominio adecuado, hasta una mala comunicación en el equipo.
Preocuparse por su código y la calidad del producto que desarrolla es un buen atributo que siempre desea alentar a otras personas.
fuente
Si codifica en C, Objective-C o C ++, puede usar el Analizador estático CLang para criticar su fuente sin ejecutarlo realmente.
Hay algunas herramientas de depuración de memoria disponibles: ValGrind, Guard Malloc en Mac OS X, Electric Fence en * NIX.
Algunos entornos de desarrollo ofrecen la opción de usar un asignador de memoria de depuración, que hace cosas como llenar páginas recién asignadas y páginas recién liberadas con basura, detectar la liberación de punteros no asignados y escribir algunos datos antes y después de cada bloque de montón, siendo el depurador se llama si el patrón conocido de esos datos cambia alguna vez.
Un tipo en Slashdot dijo que obtuvo mucho valor de la nueva línea de fuente de un solo paso en un depurador. "Eso es todo", dijo. No siempre sigo su consejo, pero cuando lo tengo me ha sido muy útil. Incluso si no tiene un caso de prueba que estimule una ruta de código poco común, puede girar una variable en su depurador para tomar tales rutas, por ejemplo, asignando algo de memoria, luego usando el depurador para establecer su nuevo puntero en NULL en lugar de dirección de memoria, luego recorriendo el controlador de fallas de asignación.
Utilice aserciones: la macro afirmar () en C, C ++ y Objective-C. Si su idioma no proporciona una función de aserción, escríbala usted mismo.
Use afirmaciones generosamente, luego déjelas en su código. Llamo afirmar () "La prueba que sigue probando". Los uso con mayor frecuencia para verificar las condiciones previas en el punto de entrada de la mayoría de mis funciones. Esa es una parte de "Programación por contrato", que está integrada en el lenguaje de programación de Eiffel. La otra parte son las condiciones posteriores, es decir, el uso de afirmar () en los puntos de retorno de la función, pero encuentro que no obtengo tanto kilometraje de eso como las condiciones previas.
También puede usar afirmar para verificar invariantes de clase. Si bien no se requiere estrictamente que ninguna clase tenga invariantes, la mayoría de las clases diseñadas con sensatez las tienen. Una clase invariante es una condición que siempre es cierta, aparte de dentro de las funciones miembro que pueden colocar temporalmente su objeto en un estado inconsistente. Tales funciones siempre deben restaurar la consistencia antes de que regresen.
Por lo tanto, cada función miembro podría verificar la invariante al entrar y salir, y la clase podría definir una función llamada CheckInvariant que cualquier otro código podría llamar en cualquier momento.
Use una herramienta de cobertura de código para verificar qué líneas de su fuente realmente se están probando, luego diseñe pruebas que estimulen las líneas no probadas. Por ejemplo, puede verificar los controladores de poca memoria ejecutando su aplicación dentro de una VM configurada con poca memoria física, y sin archivos de intercambio o muy pequeña.
(Por alguna razón, nunca tuve acceso, aunque el BeOS podía ejecutarse sin un archivo de intercambio, era muy inestable de esa manera. Dominic Giampaolo, quien escribió el sistema de archivos BFS, me instó a que nunca ejecutara el BeOS sin intercambio. No lo hago vea por qué eso debería importar, pero debe haber sido algún tipo de artefacto de implementación).
También debe probar la respuesta de su código a los errores de E / S. Intente almacenar todos sus archivos en un recurso compartido de red, luego desconecte su cable de red mientras su aplicación tiene una gran carga de trabajo. Del mismo modo, desconecte el cable, o apague la conexión inalámbrica, si se está comunicando a través de una red.
Una cosa que encuentro particularmente irritante son los sitios web que no tienen un código Javascript robusto. Las páginas de Facebook cargan docenas de pequeños archivos Javascript, pero si alguno de ellos no se descarga, la página entera se rompe. Simplemente tiene que haber alguna forma de proporcionar cierta tolerancia a fallas, por ejemplo, al volver a intentar una descarga, o para proporcionar algún tipo de respaldo razonable cuando algunos de sus scripts no se descargaron.
Intente eliminar su aplicación con el depurador o con "kill -9" en * NIX mientras está escribiendo un archivo grande e importante. Si su aplicación está bien diseñada, todo el archivo se escribirá o no se escribirá en absoluto, o tal vez si solo se escribe parcialmente, lo que se escribe no se corromperá, y los datos que se guardan serán completamente utilizables por la aplicación al volver a leer el archivo.
las bases de datos siempre tienen E / S de disco con tolerancia a fallas, pero casi ningún otro tipo de aplicación lo hace. Si bien los sistemas de archivos registrados evitan la corrupción del sistema de archivos en caso de falla de energía o fallas, no hacen nada para evitar la corrupción o la pérdida de datos del usuario final. Esa es la responsabilidad de las aplicaciones del usuario, pero casi ninguna otra que las bases de datos implementan tolerancia a fallas.
fuente
Cuando miro probar mi código, generalmente paso por una serie de procesos de pensamiento:
La forma más fácil que he encontrado para hacer esto es desarrollar mis pruebas junto con mi código. Tan pronto como he escrito incluso un fragmento de código, me gusta escribir una prueba para ello. Intentar hacer todas las pruebas después de haber codificado varios miles de líneas de código con una complejidad de código ciclomático no trivial es una pesadilla. Agregar una o dos pruebas más después de agregar algunas líneas de código es realmente fácil.
Por cierto, solo porque la compañía en la que trabajas y / o tus colegas no hacen Pruebas unitarias o TDD, no significa que no puedas probarlos, a menos que estén específicamente prohibidos. Quizás usarlos para crear código robusto será un buen ejemplo para otros.
fuente
Además de los consejos dados en las otras respuestas, sugeriría usar herramientas de análisis estático (Wikipedia tiene una lista de varias herramientas de análisis estático para varios idiomas ) para encontrar posibles defectos antes de comenzar las pruebas, así como monitorear algunas métricas relacionadas con la capacidad de prueba del código, como la complejidad ciclomática , las medidas de complejidad de Halstead y la cohesión y el acoplamiento (puede medirlos con entrada y salida de abanico).
Encontrar un código difícil de probar y hacer que sea más fácil probarlo, bueno, te facilitará la escritura de casos de prueba. Además, la detección temprana de defectos agregará valor a todas sus prácticas de garantía de calidad (que incluyen pruebas). A partir de aquí, familiarizarse con las herramientas de prueba de unidad y las herramientas de burla le facilitará la implementación de su prueba.
fuente
Podría analizar el posible uso de las Tablas de verdad para ayudarlo a definir todas las rutas potenciales en su código. Es imposible tener en cuenta todas las posibilidades en funciones complejas, pero una vez que haya establecido su manejo para todas las rutas conocidas, puede establecer un manejo para el caso contrario.
Sin embargo, la mayor parte de esta habilidad particular se aprende por experiencia. Después de haber utilizado un determinado marco durante un período de tiempo significativo, comienza a ver los patrones y las características del comportamiento que le permitirán ver un fragmento de código y ver dónde un pequeño cambio podría causar un error importante. La única forma en que puedo pensar para aumentar tu aptitud en esto es practicando.
fuente
Si, como dijiste, no necesitas pruebas unitarias, no veo un enfoque mejor que intentar descifrar tu propio código manualmente.
Intenta llevar tu código al límite . Por ejemplo, intente pasar variables a una función que exceda los límites. ¿Tiene una función que se supone que filtra la entrada del usuario? Intenta ingresar diferentes combinaciones de caracteres.
Considere el punto de vista del usuario . Intente ser uno de los usuarios que utilizará su aplicación o biblioteca de funciones.
fuente
Sus colegas deben ser realmente excepcionales para no seguir TDD o pruebas unitarias y nunca generar errores, por lo que, en cierto nivel, dudo que no estén realizando ninguna prueba unitaria ellos mismos.
Supongo que sus colegas están haciendo más pruebas de las que se están haciendo, pero debido a que la gerencia no conoce este hecho, la organización sufre como resultado porque la gerencia tiene la impresión de que no se están realizando pruebas verdaderas y que los números de errores son bajos, por lo tanto la prueba no es importante y no se programará tiempo para ello.
Hable con sus colegas e intente averiguar qué tipo de pruebas unitarias están haciendo y emule eso. En un momento posterior, puede crear prototipos de mejores formas de pruebas unitarias y atributos TDD e introducir lentamente estos conceptos al equipo para una adopción más fácil.
fuente
Debería poder obtener cobertura sobre lo que escribe, incluso si su organización no tiene cobertura total. Como tantas otras cosas en la programación, la experiencia de hacerlo una y otra vez es una de las mejores maneras de ser eficiente.
fuente
Además de todos los demás comentarios, dado que usted dice que sus colegas son buenos para escribir pruebas de ruta no feliz, ¿por qué no les pide que se emparejen con usted para escribir algunas pruebas?
La mejor manera de aprender es ver cómo se hace y extraer lo que aprende de eso.
fuente
Prueba de caja negra! Debería crear sus clases / métodos teniendo en cuenta las pruebas. Sus pruebas deben basarse en la especificación del software y deben estar claramente definidas en su diagrama de secuencia (a través de casos de uso).
Ahora, ya que es posible que no desee hacer un desarrollo basado en pruebas ...
Poner validación de entrada en todos los datos entrantes; No confíes en nadie. El marco .net tiene muchas excepciones basadas en argumentos inválidos, referencias nulas y estados inválidos. Ya debería estar pensando en usar la validación de entrada en la capa de interfaz de usuario, por lo que es el mismo truco en el middleware.
Pero realmente deberías estar haciendo algún tipo de prueba automatizada; esas cosas salvan vidas.
fuente
En mi experiencia
Unidad de prueba, si no es completamente automática, es inútil. Es más como un jefe de pelo puntiagudo podría comprar. ¿Por qué ?, porque Test Unit le prometió ahorrar tiempo (y dinero) automatizando algunos procesos de prueba. Pero, algunas herramientas de unidad de prueba hacen lo contrario, obligan a los programadores a trabajar de una manera extraña y obligan a otras a crear pruebas de extensión excesiva. La mayoría de las veces, no ahorrará horas de trabajo sino que aumentará el tiempo de traslado del control de calidad al desarrollador.
UML es otra pérdida de tiempo. una sola pizarra blanca + bolígrafo podría hacer lo mismo, más barato y rápido.
Por cierto, ¿cómo ser bueno en la codificación (y evitar errores)?
a) atomicidad. Una función que realiza una tarea simple (o algunas tareas simples). Debido a que es fácil de entender, es fácil de rastrear y es fácil de resolver.
b) Homología. Si, por ejemplo, llama a una base de datos utilizando un procedimiento de almacenamiento, haga lo mismo para el resto del código.
c) Identificar, reducir y aislar el "código creativo". La mayor parte del código es prácticamente copiar y pegar. El código creativo es lo contrario, un código que es nuevo y actúa como un prototipo, puede fallar. Este código es propenso a errores lógicos, por lo que es importante reducirlo, aislarlo e identificarlo.
d) El código "Thin Ice" es el código que usted sabe que es "incorrecto" (o potencialmente peligroso) pero que aún necesita, por ejemplo, código inseguro para un proceso de tareas múltiples. Evítalo si puedes.
e) Evite el código de recuadro negro, esto incluye el código que no ha hecho usted (por ejemplo, el marco) y la expresión regular. Es fácil perderse un error con este tipo de código. Por ejemplo, trabajé en un proyecto usando Jboss y no encontré uno sino 10 errores en Jboss (usando la última versión estable), fue un PITA encontrarlos. Evite especialmente Hibernate, oculta la implementación, de ahí los errores.
f) agregue comentarios en su código.
g) entrada del usuario como fuente de errores. identificarlo Por ejemplo, la inyección SQL es causada por una entrada del usuario.
h) Identificar el elemento malo del equipo y separar la tarea asignada. Algunos programadores son propensos a atornillar el código.
i) Evite el código innecesario. Si, por ejemplo, la clase necesita Interfaz , úsela; de lo contrario, evite agregar código irrelevante.
a) yb) son clave. Por ejemplo, tuve un problema con un sistema, cuando hice clic en un botón (guardar) no guardó el formulario. Luego hice una lista de verificación:
Y una nota al margen
fuente
Un probador y un programador enfrentan el problema desde diferentes ángulos, pero ambos roles deben probar completamente la funcionalidad y encontrar errores. Donde los roles difieren está en foco. Un probador clásico ve la aplicación solo desde el exterior (es decir, recuadro negro). Son expertos en los requisitos funcionales de la aplicación. Se espera que un programador sea un experto tanto en los requisitos funcionales como en el código (pero tiende a centrarse más en el código).
(Depende de la organización si se espera explícitamente que los programadores sean expertos en los requisitos. Independientemente, la expectativa implícita está ahí; si diseñas algo incorrecto, tú, no la persona de los requisitos, recibes la culpa).
Esta doble función de experto está afectando la mente del programador y, a excepción de los más experimentados, puede disminuir la competencia en los requisitos. Me parece que debo cambiar mentalmente de marcha para considerar a los usuarios de la aplicación. Esto es lo que me ayuda:
fuente
Creo que quieres trabajar en dos frentes. Una es política, lograr que su organización adopte pruebas en algún nivel (con la esperanza de que con el tiempo adopten más). Hable con ingenieros de control de calidad fuera de su lugar de trabajo. Encuentra listas de libros de control de calidad . Examine los artículos relevantes de Wikipedia . Familiarícese con los principios y prácticas de control de calidad. Aprender estas cosas lo preparará para presentar el caso más convincente posible en su organización. Existen buenos departamentos de control de calidad y agregan un valor considerable a sus organizaciones.
Como desarrollador individual, adopte estrategias para usar en su propio trabajo. Use TDD usted mismo mediante el desarrollo conjunto de código y pruebas. Mantenga las pruebas claras y bien mantenidas. Si se le pregunta por qué está haciendo esto, puede decir que está evitando las regresiones y mantiene su proceso de pensamiento mejor organizado (lo cual será cierto). Escribir un código comprobable es un arte , aprende. Sea un buen ejemplo para sus compañeros desarrolladores.
En parte, me estoy predicando a mí mismo aquí, porque hago mucho menos de lo que sé que debería.
fuente