O outro lado da moeda ou sobre as desvantagens dos testes de unidade

Introdução

Tanto aqui como em outros lugares na web, existem toneladas de artigos promovendo testes automatizados em geral e testes de unidade em particular. Os artigos descrevem os benefícios do teste, usá-lo para eliminar código frágil, aumentar a qualidade, migrar de sistemas antigos para novos, refatoração. E, ao mesmo tempo, quase não há menção de suas deficiências em lugar nenhum, e não há "balas de prata" na engenharia!





Na verdade, existem "balas de prata", mas foram inventadas pelos primeiros engenheiros e são percebidas por nós como chatas banalidades: "lave as mãos antes de comer", "limpe os pés", "estruture o código", " não escreva sem indentação "," localize state ", etc. No entanto, os testes não são uma "bala de prata", mas uma das ferramentas mais eficazes e amplamente utilizadas, o que significa que tem desvantagens.





Neste post tentarei estruturar e anotar exatamente as deficiências dos testes, principalmente os testes de unidade. Vou tentar não escrever sobre o mérito, pois já existem tantos materiais sobre isso, é só esticar a mão. É claro que, em algum lugar, inevitavelmente esquecerei algo importante e em algum lugar exagerarei demais. Portanto, considere este artigo mais como um convite para conversar do que algo acabado. Do meu ponto de vista, o assunto está maduro e, portanto, gostaria muito de discuti-lo em detalhes.





Por que programação funcional? Portanto, testamos quase exclusivamente as funções.





Adeus às ilusões ou 33 banalidades

Em geral, não é segredo que mesmo 100% de cobertura de teste não garante o comportamento correto do programa. Por exemplo, vamos dar uma olhada no 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

      
      



Passamos por todos os ramos, está tudo bem, mas já provamos que a função f sempre retorna um dois?





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