Recientemente tuve mi examen final para un curso de ingeniería de software para mi programa de maestría y una de las preguntas en el examen fue la siguiente:
Unit Testing is considered:
a. White-box Testing
b. Black-box Testing
c. Either
En mis 7 años de experiencia en desarrollo de software, las pruebas unitarias siempre han tenido un enfoque de caja blanca. El probador siempre ha tenido pleno conocimiento de la implementación de la unidad al escribir las pruebas. Las pruebas de caja negra siempre llegaron más tarde en las formas de integración, sistema y pruebas de aceptación.
Sin embargo, la respuesta correcta al examen (según el profesor) es que las pruebas unitarias pueden ser pruebas de caja blanca o negra.
He investigado un poco, y parece que muchos casos de "prueba de unidad de caja negra" se utilizan para describir un enfoque de prueba primero donde las pruebas de unidad se escriben antes que el código. Sin embargo, en mi opinión, esto sigue siendo una prueba de caja blanca. Si bien la implementación aún no existe, quienquiera que esté escribiendo la prueba generalmente tiene una idea bastante buena sobre cómo se implementará el código fuente.
¿Puede alguien explicarme cómo funciona la prueba de unidad de caja negra (si realmente es una cosa) y cómo difiere de la prueba de unidad de caja blanca?
fuente
While the implementation does not yet exist, whoever is writing the test generally has a pretty good idea about how the source code is going to be implemented.
- Sí, pero la prueba en sí no. La prueba de caja blanca significa probar algo interno al método o clase, como el valor de una variable. No significa que el escritor de pruebas sepa cómo se ve el código bajo prueba.Respuestas:
Su profesor tiene razón: las pruebas unitarias pueden ser de caja negra o de caja blanca. La diferencia es menos sobre lo que sabe el probador, pero más sobre cómo generar casos de prueba.
Con las pruebas de recuadro negro, solo mira la interfaz y (si existe) la especificación de un componente. Cuando una función tiene una firma
int foo(int a, int b)
, puedo generar inmediatamente algunos casos de prueba simplemente probando enteros interesantes: cero, uno, menos uno, números de varios dígitos, INT_MAX, INT_MAX - 1, etc. Las pruebas de caja negra son excelentes porque son independientes de la implementación. Pero también pueden pasar por alto casos importantes.Con una prueba de caja blanca, miro la implementación, es decir, el código fuente y genero casos de prueba a partir de eso. Por ejemplo, podría querer lograr una cobertura de ruta del 100% para una función. Luego elijo los valores de entrada para que se tomen todas las rutas. Las pruebas de caja blanca son excelentes porque pueden ejercer exhaustivamente un código, con mucha más confianza que las pruebas de caja negra. Pero podrían estar probando solo los detalles de implementación, no un comportamiento realmente importante. En algunos casos, son claramente una pérdida de tiempo.
Dado que una prueba de caja blanca se deriva de la implementación, solo se puede escribir después. Una prueba de caja negra se deriva del diseño / interfaz / especificación y, por lo tanto, se puede escribir antes o después de la implementación. TDD no es claramente caja negra o caja blanca. Dado que todo el comportamiento se expresa primero mediante una prueba y luego se implementa el código mínimo para ese comportamiento, TDD resulta en casos de prueba similares a una prueba de caja blanca. Pero cuando miramos el flujo de información, las pruebas TDD no se derivan del código fuente, sino de requisitos externos. Por lo tanto, TDD es más parecido a una caja negra.
fuente
Si está llevando a cabo un desarrollo basado en pruebas, entonces, en teoría, todas sus pruebas unitarias deberían ser de caja negra. Este es su "enfoque de prueba primero". Usted escribe el contrato (interfaz), escribe las pruebas para ese contrato, y luego el contrato se cumple con la implementación. Por lo tanto, la prueba no sabe nada, y no debe saber nada, sobre la implementación.
Después de todo, cuando escribes una prueba, ¿qué estás probando? Métodos / funciones públicas.
Si tuviera que escribir la interfaz para una clase, y luego escribir las pruebas, y luego ser atropellado por un autobús, el tipo que escribe la clase mientras está en el hospital debería poder hacerlo desde su interfaz, ¿verdad? No debería tener que tirarlo y escribir su propia interfaz y pruebas.
Cuando esto se desmorona es cuando necesitas burlarte de algo de lo que depende la implementación, pero si te encuentras en una situación en la que te estás burlando de algo que nunca está expuesto públicamente, entonces has cometido un error y necesitas mire a Dependency Injection et al . Por lo tanto, diría que las pruebas unitarias de caja blanca, no las negras, deberían ser la excepción.
Considere 'Pruebas en el inodoro: no se implementa el comportamiento de la prueba' , en el que la implementación de una clase se modifica pero las pruebas aún deben ser válidas.
Sin embargo, si necesita asegurarse de que la cobertura de su código esté activa (es decir, asegurarse de que todas las rutas condicionales se prueben dentro de la implementación), entonces absolutamente necesitaría una prueba de unidad de caja blanca, porque la única manera de saber cuál es su las rutas son mirando las rutas en la implementación.
fuente
If you were to write the interface for a class, and then write the tests, and then you get hit by a bus, the guy who writes the class while you're in hospital should be able to do so from your interface, right?
-- No exactamente. La mayoría de los contratos de API solo especifican realmente las firmas de métodos, no la semántica o el comportamiento.Yo diría que todas las pruebas unitarias bien escritas son inherentemente "recuadro negro". Claro que podría tener una implementación en mente cuando escriba la prueba, pero esa implementación puede cambiar cuando refactorice. Por lo tanto, la prueba solo debe usar API públicas durante la prueba para probar la funcionalidad, no la implementación. No le importan los detalles de implementación, por lo que es una prueba de caja negra.
Si escribo pruebas que acceden a aspectos internos o privados de la unidad bajo prueba, entonces estoy probando los detalles de implementación: estoy probando la caja blanca. Pero también estoy escribiendo pruebas frágiles que pueden romperse fácilmente cuando se cambia la implementación. Por lo tanto, estas pruebas de caja blanca son una mala idea y deben evitarse.
Conclusión: si realiza una prueba de caja blanca con pruebas unitarias, tiene pruebas mal construidas. Solo prueba de caja posterior con esas pruebas unitarias. Tu profesor tiene razón: puede ser cualquiera. Pero solo si se hace mal.
fuente
Estaba en el proceso de escribir pruebas unitarias que realizan pruebas de caja negra. Es decir, estoy probando métodos públicos en una clase y, por implicación de la lógica de prueba de resultados en los métodos privados que llaman.
Hago esto cambiando las entradas al método público que se está probando en la unidad y probando las salidas esperadas que están determinadas o mutadas por la lógica en los métodos privados compatibles, cuya implementación, mis "pruebas unitarias" no necesitan saber nada.
Por lo tanto, no hay nada que le impida realizar pruebas de recuadro negro en pruebas unitarias y las pruebas se interrumpirán si alguien se mete con la implementación de la lógica de soporte oculta. De hecho, esto parece un enfoque superior y más eficiente que una unidad de caja blanca que prueba todo en una clase por el simple hecho de hacerlo. Estoy con el profesor
fuente