Le revers de la médaille ou sur les inconvénients des tests unitaires

introduction

Ici et ailleurs sur le Web, il existe des tonnes d'articles faisant la promotion des tests automatisĂ©s en gĂ©nĂ©ral et des tests unitaires en particulier. Les articles dĂ©crivent les avantages des tests, leur utilisation pour Ă©liminer le code fragile, augmenter la qualitĂ©, migrer d'anciens systèmes vers de nouveaux, refactoriser. Et, en mĂŞme temps, il n'y a presque aucune mention de leurs lacunes nulle part, et il n'y a pas de « solution miracle Â» en ingĂ©nierie !





En fait, il existe des « balles d'argent », mais elles ont été inventées par les premiers ingénieurs, et elles sont perçues par nous comme des platitudes ennuyeuses : « se laver les mains avant de manger », « s'essuyer les pieds », « structurer le code », « ne pas écrire sans indentation", "localiser l'état", etc. Néanmoins, les tests ne sont pas une « solution miracle », mais l'un des outils les plus efficaces et les plus largement utilisés, ce qui signifie qu'il présente des inconvénients.





Dans cet article, je vais essayer de structurer et d'écrire exactement les lacunes des tests, principalement des tests unitaires. Je vais essayer de ne pas écrire sur les mérites, car il y a déjà tellement de documents à ce sujet, tendez simplement la main. Bien sûr, quelque part j'oublierai inévitablement quelque chose d'important, et quelque part j'exagère trop. Par conséquent, veuillez considérer cet article plus comme une invitation à parler que comme quelque chose de fini. De mon point de vue, le sujet est assez mûr et j'aimerais donc beaucoup en discuter en détail.





Pourquoi la programmation fonctionnelle ? Nous testons donc presque exclusivement des fonctions.





Adieu aux illusions ou 33 platitudes

En général, ce n'est un secret pour personne que même une couverture de test à 100 % ne garantit pas un comportement correct du programme. Par exemple, regardons le code :





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

      
      



Nous avons parcouru toutes les branches, tout va bien, mais avons-nous prouvé que la fonction f renvoie toujours un deux ?





, , 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