La diferencia clave, para mí, es que las pruebas de integración revelan si una característica está funcionando o está rota, ya que enfatizan el código en un escenario cercano a la realidad. Invocan uno o más métodos o características de software y prueban si actúan como se esperaba.
Por el contrario, una prueba unitaria que prueba un único método se basa en la suposición (a menudo incorrecta) de que el resto del software funciona correctamente, ya que explícitamente se burla de cada dependencia.
Por lo tanto, cuando una prueba unitaria para un método que implementa alguna característica es verde, no significa que la característica esté funcionando.
Digamos que tiene un método en algún lugar como este:
public SomeResults DoSomething(someInput) {
var someResult = [Do your job with someInput];
Log.TrackTheFactYouDidYourJob();
return someResults;
}
DoSomething
es muy importante para su cliente: es una característica, lo único que importa. Es por eso que generalmente escribe una especificación de Pepino afirmando: desea verificar y comunicar que la función funciona o no.
Feature: To be able to do something
In order to do something
As someone
I want the system to do this thing
Scenario: A sample one
Given this situation
When I do something
Then what I get is what I was expecting for
Sin duda: si la prueba pasa, puede afirmar que está entregando una función de trabajo. Esto es lo que puede llamar valor comercial .
Si desea escribir una prueba unitaria para DoSomething
usted, debe fingir (usando algunas simulaciones) que el resto de las clases y métodos están funcionando (es decir, que todas las dependencias que el método está usando funcionan correctamente) y afirmar que su método está funcionando.
En la práctica, haces algo como:
public SomeResults DoSomething(someInput) {
var someResult = [Do your job with someInput];
FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log
return someResults;
}
Puede hacer esto con la Inyección de dependencia, o con algún Método de fábrica o cualquier Marco simulado o simplemente extendiendo la clase bajo prueba.
Supongamos que hay un error en Log.DoSomething()
. Afortunadamente, la especificación de Gherkin lo encontrará y sus pruebas de punta a punta fallarán.
La función no funcionará porque Log
está rota, no porque [Do your job with someInput]
no esté haciendo su trabajo. Y, por cierto, [Do your job with someInput]
es la única responsabilidad de ese método.
Además, suponga que Log
se usa en otras 100 características, en otros 100 métodos de otras 100 clases.
Sí, 100 funciones fallarán. Pero, afortunadamente, 100 pruebas de extremo a extremo también fallan y revelan el problema. Y sí: dicen la verdad .
Es información muy útil: sé que tengo un producto roto. También es información muy confusa: no me dice nada sobre dónde está el problema. Me comunica el síntoma, no la causa raíz.
Sin embargo, DoSomething
la prueba de la unidad es verde, porque está usando un falso Log
, construido para nunca romperse. Y sí: claramente está mintiendo . Está comunicando que una característica rota funciona. ¿Cómo puede ser útil?
(Si DoSomething()
la prueba de la unidad falla, asegúrese de [Do your job with someInput]
tener algunos errores).
Supongamos que este es un sistema con una clase rota:
Un solo error romperá varias características y varias pruebas de integración fallarán.
Por otro lado, el mismo error romperá solo una prueba de unidad.
Ahora, compara los dos escenarios.
El mismo error romperá solo una prueba de unidad.
- Todas tus características que usan el roto
Log
son rojas
- Todas las pruebas unitarias son verdes, solo la prueba unitaria
Log
es roja
En realidad, las pruebas unitarias para todos los módulos que usan una función rota son verdes porque, al usar simulacros, eliminaron las dependencias. En otras palabras, corren en un mundo ideal, completamente ficticio. Y esta es la única forma de aislar errores y buscarlos. Prueba de unidad significa burlarse. Si no te estás burlando, no estás haciendo pruebas unitarias.
La diferencia
Las pruebas de integración indican lo que no funciona. Pero no sirven para adivinar dónde podría estar el problema.
Las pruebas unitarias son las únicas pruebas que le dicen dónde está exactamente el error. Para extraer esta información, deben ejecutar el método en un entorno simulado, donde se supone que todas las demás dependencias funcionan correctamente.
Es por eso que creo que su oración "¿O es solo una prueba unitaria que abarca 2 clases" está de alguna manera desplazada? Una prueba unitaria nunca debe abarcar 2 clases.
Esta respuesta es básicamente un resumen de lo que escribí aquí: las pruebas unitarias mienten, por eso las amo .