Qual é o objetivo de executar testes de unidade em um servidor de CI?

94

Por que você executaria testes de unidade em um servidor de IC?

Certamente, quando algo se compromete a dominar, um desenvolvedor já executou todos os testes de unidade antes e corrigiu quaisquer erros que possam ter ocorrido com o novo código. Não é esse o ponto dos testes unitários? Caso contrário, eles acabaram de cometer código quebrado.

    
por Steve 27.01.2016 / 14:21
fonte

9 respostas

219

Surely, by the time something gets committed to master, a developer has already run all the unit tests before and fixed any errors that might've occurred with their new code.

Ou não. Pode haver muitas razões pelas quais isso pode acontecer:

  • O desenvolvedor não tem disciplina para fazer isso
  • Eles esqueceram
  • Eles não confirmaram tudo e empurraram um conjunto de confirmações incompleto (obrigado Matthieu M.
  • Eles só executaram alguns testes, mas não o pacote inteiro (obrigado nhgrif )
  • Eles testaram em suas filiais antes da fusão (obrigado nhgrif * 2)

Mas o verdadeiro ponto é executar os testes em uma máquina que não seja a máquina do desenvolvedor. Um que esteja configurado de maneira diferente.

Isso ajuda a detectar problemas em que testes e / ou código dependem de algo específico de uma caixa de desenvolvedor (configuração, dados, fuso horário, localidade, o que for).

Outras boas razões para o CI construir testes para executar:

  • Teste em plataformas diferentes das principais plataformas de desenvolvimento, o que pode ser difícil para um desenvolvedor fazer. (obrigado TZHX )
  • Aceitação / Integração / De ponta a ponta / Testes de execução muito longa podem ser executados no servidor de IC que normalmente não seriam executados em uma caixa de desenvolvedor. (obrigado Ixrec )
  • Um desenvolvedor pode fazer uma pequena alteração antes de pressionar / confirmar (pensando que essa é uma alteração segura e, portanto, não está executando os testes). (obrigado Ixrec * 2)
  • A configuração do servidor de IC geralmente não inclui todas as ferramentas e configurações do desenvolvedor e, portanto, está mais próxima do sistema de produção
  • Os sistemas de CI criam o projeto do zero toda vez, o que significa que as construções são repetíveis
  • Uma alteração de biblioteca pode causar problemas no recebimento de dados - um servidor de IC pode ser configurado para criar bases de código dependentes all , não apenas na biblioteca
por 27.01.2016 / 14:24
fonte
73

Como um desenvolvedor que não executa todos os testes de integração e de unidade antes de se comprometer com o controle de origem, eu ofereço minha defesa aqui.

Eu teria que criar, testar e verificar se um aplicativo é executado corretamente em:

  • Microsoft Windows XP e Vista com o compilador do Visual Studio 2008.
  • Microsoft Windows 7 com o compilador do Visual Studio 2010.
    • Ah, e o MSI é construído para cada um deles.
  • RHEL 5 e 6 com 4.1 e 4.4 respectivamente (similarmente ao CentOS)
    • 7 em breve. Woop-de-woop.
  • Fedora Workstation com o GCC para as últimas três versões recentes.
  • Debian (e derivados como o Ubuntu) para as últimas três versões recentes.
  • Mac OSX nas últimas três versões recentes.
    • E os pacotes (rpm, dmg, etc)

Adicione Fortran (com os compiladores Intel e GNU), Python (e suas várias versões dependendo do sistema operacional) e os componentes do script bash / bat e, bem, eu acho que você pode ver as coisas saindo em espiral

Então, são dezesseis máquinas que eu teria que ter, apenas para fazer alguns testes algumas vezes por dia. Seria quase um trabalho em tempo integral apenas para gerenciar a infraestrutura para isso. Eu acho que quase todos concordam que isso não é razoável, especialmente multiplicando-o para o número de pessoas no projeto. Então deixamos nossos servidores de CI fazer o trabalho.

Testes de unidade não impedem que você cometa código quebrado, eles dizem se eles sabem que você quebrou alguma coisa. As pessoas podem dizer que "testes unitários devem ser rápidos", e continuar sobre princípios e padrões e metodologias de projeto, mas na realidade às vezes é melhor deixar os computadores que criamos para tarefas repetitivas e monótonas fazerem isso e só se envolverem se diga-nos que eles encontraram algo.

    
por 27.01.2016 / 14:58
fonte
22

Você pensaria que não faria isso - mas os desenvolvedores são humanos e às vezes esquecem.

Além disso, os desenvolvedores muitas vezes não conseguem extrair o código mais recente. Seus testes mais recentes podem correr bem, então, no momento do check-in, outra pessoa comete uma quebra de mudança.

Seus testes também podem depender de um recurso local (não verificado). Algo que os testes da sua unidade local não atendem.

Se você acha que todos os itens acima são fantasiosos, há um nível acima de CI (no TFS pelo menos) chamado Gated onde as compilações com testes com falha são arquivadas e não estão comprometidas com a base de código .

    
por 27.01.2016 / 14:23
fonte
22

Além da excelente resposta de Oded:

  • Você testa o código do repositório . Pode funcionar na sua máquina com seus arquivos ... que você esqueceu de cometer. Pode depender de uma nova tabela que não tenha o script de criação (por exemplo, em liquibase), alguns dados de configuração ou arquivos de propriedades.
  • Você evita problemas de integração de código. Um desenvolvedor faz o download da última versão, cria teste de unidade e integração, adiciona código, passa todos os testes em sua máquina, confirma e envia. Outro desenvolvedor acabou de fazer o mesmo. Ambas as alterações estão certas, mas quando mescladas causam um erro. Isso pode ser a fusão do repositório ou apenas que não é detectado como um conflito. Por exemplo. O Dev 1 exclui o arquivo que não foi usado. Dev dois códigos contra este arquivo e testes sem alterações no Dev 1.
  • Você desenvolve um script para implantar automaticamente a partir do repositório. Ter um script de criação e implantação universal resolve muitos problemas. Alguns desenvolvedores podem ter adicionado uma opção de lib ou compilação que não é compartilhada por todos. Isso não apenas economiza seu tempo, mas, mais importante, torna a implantação segura e previsível. Além disso, você pode voltar ao seu repositório para a versão 2.3.1 e implantar essa versão com um script que funcione com esta versão. Inclui objetos de banco de dados, como modos de exibição, procedimentos armazenados, modos de exibição e gatilhos que devem ser versionados. (Ou você não poderá voltar a uma versão viável).
  • Outros testes : como testes de integração, desempenho e de ponta a ponta. Isso pode ser lento e pode incluir ferramentas de teste como o Selenium. Você pode precisar de um conjunto completo de dados com um banco de dados real em vez de objetos simulados ou HSQL.

Uma vez trabalhei em uma empresa que tinha muitos bugs na implantação devido ao processo de mesclagem e implantação. Isso foi causado por uma estrutura proprietária estranha que dificultou os testes e o CI. Não foi uma experiência feliz descobrir que o código que funcionou perfeitamente no desenvolvimento não chegou diretamente à produção.

    
por 27.01.2016 / 16:13
fonte
14

by the time something gets committed to master

Eu geralmente configuro meu IC para rodar em cada commit. As ramificações não são mescladas no mestre até que a ramificação tenha sido testada. Se você está confiando em executar testes no master, isso abre uma janela para que a compilação seja quebrada.

A execução dos testes em uma máquina de CI é sobre resultados reproduzíveis. Como o servidor de IC tem um ambiente limpo conhecido extraído do seu VCS, você sabe que os resultados do teste estão corretos. Quando rodando localmente, você pode esquecer de cometer algum código necessário para eles passarem, ou ter um código não comprometido que os faça passar quando eles falharem.

Ele também pode economizar tempo dos desenvolvedores executando conjuntos diferentes em paralelo, especialmente se alguns forem testes lentos de vários minutos que provavelmente não serão executados localmente após cada alteração.

No meu trabalho atual, nossa implantação de produção é controlada pelo CI passando por todos os testes. Os scripts de implantação impedirão a implantação, a menos que estejam passando. Isso torna impossível acidentalmente esquecer de executá-las.

O CI que faz parte do fluxo de trabalho também sobrecarrega os desenvolvedores. Como desenvolvedor, você costuma executar um linter, um analisador estático, um teste de unidade, uma cobertura de código e um teste de integração para cada alteração? O CI pode, de forma totalmente automática e sem precisar pensar nisso - reduzindo a fadiga de decisão.

    
por 27.01.2016 / 14:29
fonte
4

No momento em que algo se compromete a dominar, um desenvolvedor já deve ter executado todos os testes de unidade ... mas e se eles não tiverem? Se você não executar os testes de unidade no servidor de CI, você não saberá até que outra pessoa faça as alterações na máquina e descubra que os testes acabaram de ser executados.

Além disso, o desenvolvedor pode ter cometido um erro e referenciado um recurso local específico para sua máquina. Quando eles verificam o código e a execução do IC falha, o problema é identificado imediatamente e pode ser corrigido.

    
por 27.01.2016 / 14:24
fonte
3

Assumindo (ao contrário de outras respostas) que os desenvolvedores são bastante disciplinados e executam testes de unidade antes de cometer, pode haver vários motivos:

  • executar testes de unidade pode levar muito tempo para uma configuração especial. Por exemplo, executar testes de unidade com verificador de memória (como o valgrind) pode levar muito mais tempo. Embora todos os testes de unidade estejam passando, a verificação de memória pode falhar.
  • o resultado não é tão importante para algumas configurações especiais - por exemplo, a execução de testes de unidade para verificar a cobertura de código requer sinalizadores de compilação especiais. Para desenvolvedores normais, a cobertura de código não é tão importante - é mais para as pessoas que estão cuidando de que o código mantém certa qualidade, como líderes de equipe.
por 27.01.2016 / 14:33
fonte
3

É possível imaginar casos em que a mudança A não quebra o teste e a mudança B não quebra o teste, mas A e B juntos fazem. Se A e B forem feitos por diferentes desenvolvedores, somente o servidor do CI detectará o novo bug. A e B podem até ser duas partes da mesma sentença mais longa.

Imagine um trem impulsionado pelas duas locomotivas A e B. Talvez uma seja mais que suficiente e essa é a correção a ser aplicada. No entanto, se as duas "correções" forem aplicadas removendo ambas, o trem não se moverá.

Além disso, nem todos os desenvolvedores executam todos os testes unitários, enquanto a maioria dos bons desenvolvedores o faz.

    
por 28.01.2016 / 09:11
fonte
2

Vamos fazer uma pergunta equivalente:

Why would you build the code on a CI server?

Surely, by the time something gets committed to master, a developer has already built the code before and fixed any errors that might've occurred with their new code. Isn't that the point of building code? Otherwise they've just committed broken code.

Existem vários motivos para fazer o CI, mas o ponto principal do IC é ter uma ideia do estado do código ao longo do tempo. O principal benefício (de vários) que isso oferece, é que podemos descobrir quando a compilação se quebra, descobrir o que a quebrou e depois consertá-la.

Se o código nunca estiver quebrado, por que usamos o CI? Para fornecer compilações para testes, as construções noturnas seriam boas o suficiente.

    
por 29.01.2016 / 13:59
fonte