¿Qué es la prueba de unidad de caja negra?

11

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?

cabina trasera
fuente
44
¿Cómo aclaró el profesor esto cuando les preguntaste sobre esto? (vea también ¿Por qué las preguntas de la entrevista hacen que la Ingeniería del Software sea deficiente? )
gnat
"el que está escribiendo la prueba en general tiene una idea bastante buena de cómo se va a implementar la prueba" - no se trata de si usted sabe cómo se implementa la prueba, pero si usted sabe (blanco) o no (negro) cómo lo Estás probando está implementado.
Jesper
@Jesper lo siento. Quise decir "cómo se implementará el código fuente". Lo he arreglado en la pregunta.
backcab
2
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.
Robert Harvey

Respuestas:

20

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.

amon
fuente
3
"Dado que una prueba de caja blanca se deriva de la implementación, solo se puede escribir después" , bueno, si voy a escribir una prueba fallida en estilo TDD para la próxima nueva característica que me gustaría agregar a mi función o clase existente , Miro primero la implementación actual para aprender lo que no es compatible hasta ahora, para poder diseñar una prueba más significativa, inicialmente fallida. A esto lo llamo un enfoque de prueba de caja blanca, no una prueba escrita después. (Sin embargo, +1 de mi parte).
Doc Brown
4

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.

AdamJS
fuente
2
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.
Robert Harvey
Tienes razón; Supuse que su interfaz incluiría la especificación de la que fue escrita, no literalmente solo el texto de MyClassInterface.
AdamJS
@RobertHarvey es cierto que la mayoría de las interfaces no describen explícitamente la semántica o el comportamiento, pero creo que generalmente está ahí implícitamente. Si no estuviera allí, entonces el código que requiere cierta semántica no podría depender de la abstracción. Y no hay nada que detenga las interfaces, incluidos los detalles de la semántica y el comportamiento como comentarios / docblocs. Por ejemplo, vea github.com/php-fig/http-message/blob/master/src/…
bdsl
3

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.

David Arno
fuente
1

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

Shooresh
fuente