¿Se considera que una prueba de unidad es frágil si falla cuando cambia la lógica de negocios?

19

Por favor vea el código de abajo; se evalúa para ver si una persona con género de mujer es elegible para la oferta1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Esta prueba de unidad tiene éxito. Sin embargo, fallará si 'Offer1' se ofrece a las mujeres en el futuro.

Es aceptable decir: si la lógica de negocios que rodea la oferta 1 cambia, la prueba de la unidad debe cambiar. Tenga en cuenta que en algunos casos (para algunas ofertas) la lógica de negocios se cambia en la base de datos de esta manera:

update Offers set Gender='M' where offer=1;

y en algunos casos en el modelo de dominio como este:

if (Gender=Gender.Male)
{
  //do something
}

Tenga en cuenta que, en algunos casos, la lógica del dominio subyacente ofrece cambios con regularidad y, en algunos casos, no.

    
pregunta w0051977 24.12.2018 - 13:02
fuente

2 respuestas

65

Esto no es frágil en el sentido habitual. Una prueba de unidad se considera frágil si se rompe debido a cambios en la implementación que no afectan el comportamiento bajo prueba. Pero si la lógica de negocios en sí cambia, entonces una prueba de esta lógica se supone para romper.

Dicho esto, si la lógica de negocios cambia a menudo, quizás no sea apropiado codificar las expectativas en las pruebas unitarias. En su lugar, podría probar si las configuraciones en la base de datos afectan las ofertas como se esperaba.

El nombre de la prueba Returns False When Given A Person With A Gender Of Female no describe una regla de negocios. Una regla de negocios sería algo así como Offers Applicable to M should not be applied to persons of gender F .

Por lo tanto, podría escribir una prueba que confirme que si una oferta se define como solo aplicable a personas de tipo M, entonces no se indicará que una persona de tipo F es elegible para ello. Esta prueba garantizará que la lógica funcione incluso si cambia la configuración de las ofertas específicas.

    
respondido por el JacquesB 24.12.2018 - 13:28
fuente
11

Cuando la propiedad está definida en la base de datos de producción (o un clon para la prueba), esto no es una prueba de unidad . Una prueba de unidad verifica una unidad de trabajo y no requiere un estado externo particular para funcionar. Esto supone que Offer1 está definido en la base de datos como una oferta solo para hombres. Ese es el estado externo. Así que esto es más una prueba de integración , específicamente una system o aceptación . Tenga en cuenta que las pruebas de aceptación a menudo no están programadas (no se ejecutan en un marco de prueba, sino que son realizadas manualmente por seres humanos).

Cuando la propiedad se define en el modelo de dominio con una declaración if , la misma prueba es una prueba de unidad. Y puede ser frágil. Pero el verdadero problema es que el código es frágil. Como regla general, su código será más resistente si el comportamiento del negocio es configurable en lugar de codificado. Debido a que una implementación rápida para corregir un pequeño error de codificación debería ser rara. Pero un requisito comercial que cambia sin previo aviso es solo un martes (algo que sucede semanalmente).

Es posible que esté utilizando un marco de prueba de unidad para ejecutar la prueba. Pero los marcos de pruebas unitarias no se limitan a ejecutar pruebas unitarias. Pueden y también ejecutan pruebas de integración.

Si estuvieras escribiendo una prueba de unidad, crearías tanto person como offer1 desde cero sin depender del estado de la base de datos. Algo como

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

Tenga en cuenta que esto no cambia según la lógica empresarial. No está afirmando que offer1 rechaza a las mujeres. Está haciendo que offer1 sea el tipo de oferta que rechaza a las mujeres.

Puede crear y configurar la base de datos como parte de la prueba. En C #, utilizando NUnit, o en JUnit de Java, configuraría la base de datos en un método Setup . Presumiblemente, su marco de prueba tiene una noción similar. En ese método, podría insertar registros en la base de datos con SQL.

Si es difícil para usted escribir código que sustituya una base de datos de prueba por la base de datos de producción, suena como una debilidad de prueba en su aplicación. Para las pruebas, sería mejor usar algo como inyección de dependencia que permita la sustitución. Luego, podría escribir pruebas que sean independientes de las reglas comerciales actuales.

Un beneficio adicional de esto es que a menudo es más fácil para el propietario de la empresa (no necesariamente el propietario de la empresa, más como la persona responsable de este producto en la jerarquía corporativa) configurar las reglas de negocios directamente. Porque si tiene este tipo de marco técnico, es fácil permitir que el propietario de la empresa utilice una interfaz de usuario (UI) para configurar la oferta. El propietario del negocio seleccionaría la limitación en la interfaz de usuario y emitiría la llamada markLimitedToGender("M") . Luego, cuando la oferta se mantiene en la base de datos, almacenaría esto. Pero no necesitarías almacenar la oferta para usarla. Por lo tanto, sus pruebas podrían crear y configurar una oferta que no existe en la base de datos.

En su sistema, como se describe, el propietario del negocio tendría que presentar una solicitud al grupo técnico, que emitiría el SQL apropiado y actualizaría las pruebas. O el grupo técnico tiene que editar su código y sus pruebas (o las pruebas luego codificar). Eso parece un enfoque bastante pesado. Puedes hacerlo. Pero su software (no solo sus pruebas) sería menos frágil si no tuviera que hacerlo.

TL; DR : puede escribir pruebas como esta, pero es mejor que escriba su software para no tener que hacerlo.

    
respondido por el mdfst13 24.12.2018 - 18:00
fuente

Lea otras preguntas en las etiquetas