Qual è lo scopo di eseguire unit test su un server CI?


98

Perché dovresti eseguire unit test su un server CI?

Sicuramente, quando qualcosa si impegna a padroneggiare, uno sviluppatore ha già eseguito tutti i test unitari in precedenza e risolto eventuali errori che potrebbero essersi verificati con il nuovo codice. Non è questo il punto dei test unitari? Altrimenti hanno appena commesso un codice non funzionante.


51
Ai nostri sviluppatori non è consentito impegnarsi a padroneggiare. Spingono verso un ramo di funzionalità, il server CI si fonde con il master ed esegue i test. Se ci riusciranno, allora le modifiche vengono unite da padroneggiare. Quindi il codice con i test rotti non può essere sul master ...
Boris the Spider

2
@BoristheSpider - davvero un ottimo flusso di lavoro. masterdovrebbe sempre essere sano e preferibilmente distribuito automaticamente su ciascuna unione in un ambiente di gestione temporanea per test di qualità e test interni.
Per Lundberg,

130
"Sicuramente, quando qualcosa si impegna a padroneggiare, uno sviluppatore ha già eseguito tutti i test unitari in precedenza e risolto eventuali errori che potrebbero essersi verificati con il loro nuovo codice." In quale mondo fantastico vivi?
jpmc26,

5
In alcuni settori, la parte importante non è solo quella di eseguire i test sul codice, ma di eseguire i test sui binari . Eseguendo i test sull'output CI, è possibile garantire che il prodotto consegnato funzioni, poiché l'esatto binario ricevuto dal client è quello che ha superato tutti i test. Sembra banale, ma a volte questo può avere un effetto (uno che ho visto è l'offuscamento; su progetti complessi, o quando impostato in modo strano, può causare problemi nella build offuscata che non c'erano nella versione pulita).
anaximander,

5
"Sicuramente, quando qualcosa si impegna a padroneggiare, uno sviluppatore ha già eseguito tutti i test unitari in precedenza e risolto eventuali errori che potrebbero
essersi

Risposte:


223

Sicuramente, quando qualcosa si impegna a padroneggiare, uno sviluppatore ha già eseguito tutti i test unitari in precedenza e risolto eventuali errori che potrebbero essersi verificati con il nuovo codice.

O no. Ci possono essere molti motivi per cui questo può accadere:

  • Lo sviluppatore non ha la disciplina per farlo
  • Hanno dimenticato
  • Non hanno commesso tutto e hanno spinto un set di commit incompleto (grazie Matthieu M.
  • Hanno eseguito solo alcuni test, ma non l'intera suite (grazie nhgrif )
  • Hanno testato sul loro ramo prima della fusione (grazie nhgrif * 2)

Ma il vero punto è eseguire i test su una macchina che non è la macchina sviluppatore. Uno che è configurato in modo diverso.

Questo aiuta a individuare i problemi in cui i test e / o il codice dipendono da qualcosa di specifico per una casella dello sviluppatore (configurazione, dati, fuso orario, impostazioni internazionali, qualunque cosa).

Altri buoni motivi per cui i build CI eseguono test:

  • Test su diverse piattaforme diverse dalle principali piattaforme di sviluppo, che può essere difficile per uno sviluppatore. (grazie TZHX )
  • Accettazione / Integrazione / End-to-end / Test veramente lunghi possono essere eseguiti sul server CI che normalmente non verrebbero eseguiti su una casella di sviluppo. (grazie Ixrec )
  • Uno sviluppatore può apportare una piccola modifica prima di eseguire il push / commit (pensando che si tratti di una modifica sicura e quindi non esegue i test). (grazie Ixrec * 2)
  • La configurazione del server CI di solito non include tutti gli strumenti e la configurazione dello sviluppatore ed è quindi più vicina al sistema di produzione
  • I sistemi CI creano ogni volta il progetto da zero, il che significa che le build sono ripetibili
  • Una modifica della libreria potrebbe causare problemi a valle: un server CI può essere configurato per creare tutte le basi di codice dipendenti, non solo quella della libreria

36
Altre ragioni comuni: 1) Il server CI può eseguire test di integrazione / accettazione di alto livello che impiegano troppo tempo affinché gli sviluppatori li eseguano sempre. 2) Lo sviluppatore li ha eseguiti e poi ha apportato una piccola modifica prima di spingere che erano molto sicuri che non avrebbero rotto nulla, ma vogliamo essere certi.
Ixrec,

11
Una modifica a una dipendenza spesso esegue anche tutte le build a valle. Se una modifica apportata da uno sviluppatore interrompe qualcosa a valle, non si vede facilmente quando si modifica una libreria (diciamo cambiando un tipo di dati sottostante da un SortedSet a un HashSet (fornendo solo il contratto di Set) e qualcuno a valle ha lavorato sul presupposto errato che il set è stato ordinato). Non eseguire i test (downstream) sul server CI avrebbe lasciato quel bug fester per un po '.

2
@MichaelT Buona cattura. Questa è in realtà la causa di> 90% dei nostri guasti CI al giorno d'oggi, non sono sicuro di come l'ho dimenticato ...
Ixrec,

34
Inoltre, eseguirli in un ambiente CI significa in genere impostare il progetto da zero , assicurando che la build sia ripetibile .
Margarciaisaia,

5
Inoltre, potrebbero essere commessi due cambiamenti che sono stati testati separatamente separatamente, ma si interrompono (ad esempio uno rimuovendo un'API inutilizzata e l'altro che inizia a usarlo).
Simon Richter,

74

Come sviluppatore che non esegue tutti i test di integrazione e unità prima di impegnarsi nel controllo del codice sorgente, offro qui la mia difesa.

Dovrei costruire, testare e verificare che un'applicazione funzioni correttamente su:

  • Microsoft Windows XP e Vista con compilatore Visual Studio 2008.
  • Microsoft Windows 7 con compilatore Visual Studio 2010.
    • Oh, e l'MSI costruisce per ognuno di quelli.
  • RHEL 5 e 6 rispettivamente con 4.1 e 4.4 (similmente a CentOS)
    • 7 presto. Woop-de-woop.
  • Fedora Workstation con GCC per le ultime tre versioni recenti.
  • Debian (e derivati ​​come Ubuntu) per le ultime tre versioni recenti.
  • Mac OSX nelle ultime tre versioni recenti.
    • E i pacchetti (rpm, dmg, ecc.)

Aggiungi in Fortran (con entrambi i compilatori Intel e GNU), Python (e le sue varie versioni a seconda del sistema operativo) e componenti di script bash / bat e, beh, penso che tu possa vedere le cose esplodere

Quindi sono sedici macchine che dovrei avere, solo per eseguire alcuni test un paio di volte al giorno. Sarebbe quasi un lavoro a tempo pieno solo per gestire l'infrastruttura per quello. Penso che quasi tutti sarebbero d'accordo sul fatto che sia irragionevole, soprattutto moltiplicandolo per il numero di persone nel progetto. Quindi lasciamo che i nostri server CI facciano il lavoro.

I test unitari non ti impediscono di commettere un codice rotto, ti dicono se sanno che hai rotto qualcosa. Le persone possono dire "i test unitari dovrebbero essere veloci" e andare avanti sui principi, i modelli e le metodologie di progettazione, ma in realtà a volte è meglio lasciare che i computer che abbiamo progettato per compiti ripetitivi e monotoni facciano quelli e vengano coinvolti solo se dicci che hanno trovato qualcosa.


3
Codice test unit test non configurazioni. Sarebbe seriamente inerte da parte tua aggiungere un nuovo test e lanciarlo sul muro senza nemmeno eseguirlo localmente prima ...
Robbie Dee,

33
@RobbieDee Temo di non vedere il tuo punto? Non suggerisco di creare nuovi test senza testarli localmente, o semplicemente commettere ciecamente cose al controllo del codice sorgente senza testarli da soli, e vorrei eseguire i test sulla mia macchina - ma è necessario testare la "configurazione" per un comportamento coerente , ed è meglio farlo relativamente rapidamente quando la mente dello sviluppatore è ancora in quell'area piuttosto che trovare un problema quando il team che utilizza principalmente i Mac si sveglia a quattromila miglia di distanza e aggiorna le loro copie.
TZHX,

7
@RobbieDee Direi che TZHX eseguirà tutti i test localmente se potessero farlo, ma non possono . Dal momento che TZHX non può, eseguono alcuni test localmente (quelli che possono essere eseguiti sul loro sistema di sviluppo e abbastanza brevi o più rilevanti per il codice modificato, per esempio), e lasciano funzionare l'intera batteria sul sistema CI. Abbastanza ragionevole
Muru,

11
@RobbieDee: crede nei test unitari. Quindi li prova sul suo Macbook air e passa e controlla. I server CI che eseguono Red Hat, Solaris e Windows eseguono nuovamente questi test. Non è bello sapere che ciò che hai testato funziona anche su piattaforme di produzione?
Slebetman,

2
@RobbieDee: ho spesso scritto test unit che erano specifici di un determinato compilatore su una determinata piattaforma. Considera ad esempio un sottosistema grafico che utilizza le istruzioni specifiche della CPU AMD (il concorrente Intel) che sono disponibili solo su g ++ (compilatore GNU C ++) versione 4.5 o successive, ma mi capita di lavorare su una CPU Atom e ICC (Intel C ++ Compiler). Non avrebbe senso eseguire i test AMD / g ++ 4.5 ogni volta su quella macchina, tuttavia è necessario testare il codice prima del rilascio; inoltre il mio codice indipendente dalla CPU deve essere testato per una corretta interoperabilità. Certo, ci sono macchine virtuali ed emulatori, ...
phresnel

23

A parte l'ottima risposta di Oded:

  • Si verifica il codice dal repository . Potrebbe funzionare sul tuo computer con i tuoi file ... che hai dimenticato di impegnare. Può dipendere da una nuova tabella che non ha lo script di creazione (ad esempio in liquibase), alcuni dati di configurazione o file delle proprietà.
  • Si evitano problemi di integrazione del codice. Uno sviluppatore scarica l'ultima versione, crea unità e test di integrazione, aggiunge codice, supera tutti i test nella sua macchina, esegue il commit e spinge. Un altro sviluppatore ha appena fatto lo stesso. Entrambe le modifiche sono valide da sole ma quando unite causa un errore. Potrebbe trattarsi della fusione del repository o semplicemente del fatto che non viene rilevato come conflitto. Ad esempio Dev 1 elimina il file che non è stato utilizzato affatto. Dev 2 codici su questo file e test senza modifiche Dev 1.
  • Si sviluppa uno script da distribuire automaticamente dal repository. Avere un edificio universale e distribuire script risolve molti problemi. Alcuni sviluppatori potrebbero aver aggiunto un'opzione lib o di compilazione che non è condivisa da tutti. Questo non solo ti fa risparmiare tempo, ma soprattutto, rende la distribuzione sicura e prevedibile. Inoltre, puoi tornare nel tuo repository alla versione 2.3.1 e distribuire questa versione con uno script che funziona con questa versione. Include oggetti di database come visualizzazioni, stored procedure, viste e trigger che devono essere sottoposti a versione. (O non sarai in grado di tornare a una versione praticabile).
  • Altri test : come l'integrazione, le prestazioni e le prove end-to-end. Questo può essere lento e potrebbe includere strumenti di test come il selenio. Potrebbe essere necessario un set completo di dati con un database reale anziché oggetti finti o HSQL.

Una volta ho lavorato su un'azienda che aveva molti bug sulla distribuzione a causa del processo di fusione e distribuzione. Ciò è stato causato da una strana struttura propietaria che ha reso difficili i test e la CI. Non è stata una felice esperienza scoprire che il codice che ha funzionato perfettamente nello sviluppo non è arrivato alla produzione.


Sì, dimenticare semplicemente di impegnare alcune delle modifiche è molto comune. Direi che dimenticare di "svn aggiungere" nuovi file e quindi dimenticare di impegnarli in un secondo momento è il modo più popolare per ottenere una compilazione automatica non riuscita.
sharptooth,

22

Penseresti di no, ma gli sviluppatori sono umani e talvolta dimenticano.

Inoltre, gli sviluppatori spesso non riescono a estrarre il codice più recente. I loro ultimi test potrebbero essere eseguiti correttamente, quindi al momento del check-in, qualcun altro commette un cambiamento decisivo.

I test possono anche basarsi su una risorsa locale (non selezionata). Qualcosa che i test delle tue unità locali non avrebbero raccolto.

Se pensi che tutto quanto sopra sia fantasioso, c'è un livello superiore a CI (almeno su TFS) chiamato Gated in cui le build che hanno test falliti sono accantonate e non sono impegnate nella base di codice.


7
Ho visto più oops che ho dimenticato di commettere quei fallimenti CI che mi interessa ammettere.
Dan Neely,

@DanNeely Per essere onesti, è meglio che ti venga preso a calci nel culo dal responsabile della costruzione perché ti sei dimenticato di raccontargli qualcosa ... :-)
Robbie Dee,

3
Questo è uno dei motivi per cui amo CI. Trovare e correggere i propri ooops è molto meglio che chiedere a qualcun altro di trovarli per te.
Dan Neely,

14

quando qualcosa si impegna a padroneggiare

Di solito imposto il mio CI per l'esecuzione su ogni singolo commit. I rami non vengono uniti in master fino a quando il ramo non è stato testato. Se fai affidamento sull'esecuzione di test sul master, ciò apre una finestra in cui la build deve essere interrotta.

L'esecuzione dei test su una macchina CI riguarda risultati riproducibili. Poiché il server CI ha un ambiente pulito noto estratto dal tuo VCS, sai che i risultati del test sono corretti. Quando si esegue localmente, è possibile dimenticare di eseguire il commit di un codice necessario per il loro passaggio o di disporre di un codice di cui non è stato eseguito il commit che li fa passare in caso di errore.

Inoltre, può far risparmiare tempo agli sviluppatori eseguendo diverse suite in parallelo, soprattutto se alcuni sono test lenti da più minuti che non possono essere eseguiti localmente dopo ogni modifica.

Nel mio lavoro attuale la nostra distribuzione in produzione è soggetta al CI che supera tutti i test. Gli script di distribuzione impediranno la distribuzione a meno che non stiano passando. Ciò rende impossibile dimenticare accidentalmente di eseguirli.

La CI che fa parte del flusso di lavoro si fa carico anche degli sviluppatori. Come sviluppatore, di solito esegui una linter, un analizzatore statico, un test unitario, una copertura del codice e un test di integrazione per ogni singola modifica? L'IC può, in modo completamente automatico e senza pensarci, riducendo l'affaticamento delle decisioni.


1
Non dovresti davvero fare test di unità lenti - questo viola i PRIMI principi.
Robbie Dee,

4
@RobbieDee: penso che di solito il server CI esegua tutti i test, non solo i test unitari.
RemcoGerlich,

4
@RobbieDee: in teoria tutti i test unitari sono veloci. In pratica .... Indipendentemente da ciò, CI può e deve eseguire tutti i test: linters, analisi statiche, unit test, test di integrazione.
Daenyth,

2
@RobbieDee Ovviamente le specifiche di configurazione varieranno da squadra a squadra. Anche quando le build impiegano più minuti, è spesso possibile eseguire più di quelle build in parallelo. Dato un singolo codice base monolitico potrebbe essere uno svantaggio più grande, ma l'IME non è una barriera.
Daenyth,

1
@RobbieDee Penso che dipenda maggiormente dalla tua architettura. L'ho visto funzionare a mano per un team di ingegneri di ~ 80, ma questo è con sotto-team ben definiti per le aree di prodotto.
Daenyth,

4

Quando qualcosa si impegna a padroneggiare, uno sviluppatore avrebbe già dovuto eseguire tutti i test unitari ... ma se non lo fossero? Se non si eseguono i test unitari sul server CI, non lo si saprà fino a quando qualcun altro non avvierà le modifiche sulla propria macchina e scoprirà i test appena falliti.

Inoltre, lo sviluppatore potrebbe aver commesso un errore e fare riferimento a una risorsa locale specifica per la propria macchina. Quando eseguono il check in nel codice e l'esecuzione dell'elemento della configurazione non riesce, il problema viene immediatamente identificato e può essere corretto.


3

Supponendo (contrariamente ad altre risposte) che gli sviluppatori siano abbastanza disciplinati ed eseguano unit test prima di impegnarsi, ci possono essere diversi motivi:

  • l'esecuzione di test unitari può richiedere molto tempo per alcune configurazioni speciali. Ad esempio, l'esecuzione di unit test con il controllo memoria (come valgrind) può richiedere molto più tempo. Sebbene tutti i test unitari stiano passando, il controllo della memoria può fallire.
  • il risultato non è così importante per alcune impostazioni speciali, ad esempio l'esecuzione di test di unità per verificare la copertura del codice richiede flag di compilazione speciali. Per gli sviluppatori normali, la copertura del codice non è così importante: è più per le persone che si prendono cura che il codice mantenga una certa qualità, come i lead del team.

3

È possibile immaginare casi in cui la modifica A non interrompe il test e la modifica B non interrompe il test, ma A e B insieme lo fanno. Se A e B sono creati da sviluppatori diversi, solo il server CI rileverà il nuovo bug. A e B possono anche essere due parti della stessa frase più lunga.

Immagina un treno guidato dalle due locomotive A e B. Forse uno è più che sufficiente e questa è la soluzione da applicare. Tuttavia, se vengono applicate le due "correzioni" rimuovendo entrambe, il treno non si sposterà.

Inoltre, non tutti gli sviluppatori eseguono tutti i test delle unità, mentre la maggior parte degli sviluppatori lo fa.


2

Facciamo una domanda equivalente:

Perché dovresti creare il codice su un server CI?

Sicuramente, quando qualcosa si impegna a padroneggiare, uno sviluppatore ha già creato il codice prima e risolto eventuali errori che potrebbero essersi verificati con il loro nuovo codice. Non è questo il punto di costruire il codice? Altrimenti hanno appena commesso un codice non funzionante.


Ci sono diverse ragioni per fare CI, ma il punto principale di CI è avere un'idea di quale sia lo stato del codice nel tempo. Il vantaggio principale (tra i tanti) fornito da questo è che possiamo scoprire quando la build si rompe, capire cosa l'ha rotto e quindi risolverlo.

Se il codice non viene mai infranto, perché usiamo anche CI? Per fornire build per i test, le build notturne sarebbero abbastanza buone.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.