La otra cara de la moneda o sobre las desventajas de las pruebas unitarias

Introducción

Tanto aquí como en otros lugares de la web, hay toneladas de artículos que promueven las pruebas automatizadas en general y las pruebas unitarias en particular. Los artículos describen los beneficios de probar, usarlo para eliminar código frágil, aumentar la calidad, migrar de sistemas antiguos a nuevos, refactorizar. Y, al mismo tiempo, casi no se mencionan sus deficiencias en ninguna parte, ¡y no hay "soluciones mágicas" en ingeniería!





De hecho, hay "balas de plata", pero fueron inventadas por los primeros ingenieros, y nosotros las percibimos como trivialidades aburridas: "lávate las manos antes de comer", "límpiate los pies", "estructura el código", " no escriba sin sangría "," localizar estado ", etc. Sin embargo, las pruebas no son una "solución milagrosa", sino una de las herramientas más efectivas y ampliamente utilizadas, lo que significa que tiene inconvenientes.





En este post intentaré estructurar y anotar exactamente las deficiencias de las pruebas, principalmente las pruebas unitarias. Trataré de no escribir sobre los méritos, porque ya hay muchos materiales sobre esto, solo extienda la mano. Por supuesto, en algún lugar olvidaré inevitablemente algo importante, y en algún lugar exageraré demasiado. Por lo tanto, considere este artículo más como una invitación a hablar que como algo terminado. Desde mi punto de vista, el tema está bastante maduro y, por lo tanto, me gustaría mucho discutirlo en detalle.





¿Por qué la programación funcional? Por eso probamos casi exclusivamente funciones.





Adiós a las ilusiones o 33 tópicos

En general, no es un secreto que ni siquiera el 100% de la cobertura de las pruebas garantiza el correcto comportamiento del programa. Por ejemplo, echemos un vistazo al código:





def f( a, b):
    x = 0
    if a:
        x += 2
    else:
        x += 0
    
    if b:
        x += 2
    else:
        x += 0

    return x

#   

assert f(True, False) == 2
assert f(False, True) == 2

      
      



Pasamos por todas las ramas, todo está bien, pero ¿hemos probado que la función f siempre devuelve un dos?





, , 100% , , , , , . - - . - , "" .





property-base testing: QuickCheck Haskell, GAST Clean, Kotlintest, QCheck Ocaml, Hypothesis Python' . . , : , .





, -, , . Geant4 "" (), " " ( ) ( 5 , ).





, , - - . , 20 000 , , — 50 000 . , .





, property-based testing — , , . QuickCheck John Hughes — Building on developers' intuitions (...) | Lambda Days 19. , ...





, — : , , . , .





, , : ?





propertyDoubleEq :: Double -> bool
propertyDoubleEq x = (x == x)
      
      



, - - , , , .





2 + 2 = 5? ?

, , , . Jef239.





, - , , . - , , , copy-paste:





string monthName(unsigned int n) {
    static vector<string> months = {"", "", ... };

    return months[n % months.size()];
}

void testMonthNames() {
    assert( monthName(0) == "");
    ...
}
      
      



, , "" . , , : , .





, - " ". , , , . , .





, , , . , , - !





, — , .





- —

, — , . , — , - , :





  1. - . , - , "" , , .





  2. - . , . , , , , .





  3. - , , (. 1). , , . , !





, , , , . . , , , . , , .





  1. - . , . , . -, , , .





— , .





, , - — , , .





- —

, , . , , .





- , , , . , , , , - . :





  1. . , , — , .. . write-check-correct loop — , .



    , Ocaml — , , - "" — () . -, , .





  2. . - , - .





  3. CI - - CI , - , . , , , PR .





, - -. , .





- —

, -, - , . , , , , . , , , , . - WindowMaker, Quake I, Heroes 2 , , . , TeX, , .





, -. , . , — " , ".





, - , , . , , - . This does not add business value, right?





, — , - - , , : . — , , Python 2 Python 3 Boost, . , !





: , , - . .





, "" — , , .





, . , . , , mutation testing, - .





, , - , , — , , , . , , . , , , - .





, - — , , . " – , , ".





" ", , , IDE , . , , - , . , , , , , . , , - , .





, , . , , . !








All Articles