Test automatico "tutte le modifiche sono contrassegnate da funzionalità", possibile?

1

Diciamo che nel tentativo di migliorare la qualità, il tuo team è d'accordo sulla seguente politica:

  • tutti i commit al ramo master (diretto o tramite richiesta pull) devono essere classificati come bugfix o modifiche alle funzionalità; mai entrambi allo stesso tempo.

  • per distinguere facilmente i due, i messaggi di commit devono iniziare con ad es. [bug 123] o [feature 456] , rispettivamente

  • nelle funzioni commette, tutte le modifiche al codice devono essere contrassegnate da funzionalità (utilizzando un qualche tipo di strumento per le impostazioni dell'applicazione come NFig ). L'idea è che mentre il flag funzione è disattivato, il commit non dovrebbe cambiare il comportamento dell'app in alcun modo.

EDIT: si presume che le flag con funzionalità abbiano vita breve e solo a scopo di rilascio. Martin Fowler chiama quei commutatori di rilascio .

Quindi, ad esempio, una funzione commuta in questo modo ...

function existingCode() {
   // existing stuff

+   doSomethingNew();  // <--- NEW 

   // more exiting stuffstuff
}

... sarebbe in violazione della politica perché doSomethingNew() introduce un cambiamento immediato nel comportamento. Feature-flagging la modifica come questa ...

function existingCode() {
   // existing stuff

+  if (Config.FeatureFlags.NewFeature456)
+  {  
+    doSomethingNew();  // <--- NEW 
+  }    
   // more exiting stuffstuff
}

... sarebbe conforme alla politica: non vi è alcun cambiamento nel comportamento finché non viene abilitato il flag di funzionalità NewFeature456 (e quindi nessun rischio di rotture accidentali, perdite di funzionalità ecc.)

La mia domanda è: sarebbe ipotizzabile applicare il criterio flag di funzionalità con un test automatico ?

Il modo in cui immagino che un test come questo funzioni è, approssimativamente:

  • input: git repo, commit hash, nome del flag di funzionalità
  • build repo con e senza commit (flag funzione disabilitato in entrambi)
  • controlla se entrambe le build si comportano allo stesso modo

L'ultima parte "comportarsi allo stesso modo" è ovviamente la parte difficile. Qui viene in mente una serie di cose, dall'esecuzione di una serie di altri test automatizzati all'analisi del codice - qualcosa come confrontare gli AST di entrambe le build (che potrebbero risultare difficili).

Potrebbe funzionare? È già stato fatto prima?

    
posta Max 29.07.2018 - 04:33
fonte

3 risposte

1

Penso che manchi totalmente la causa principale del tuo problema. Immagino che il tuo vero problema sia questo:

vuoi che le funzioni diventino attive solo quando qualcuno che non è uno sviluppatore (gestione?) decide che è il momento giusto.

La soluzione, IMO, NON deve ingombrare il tuo codice con controlli distrattivi e leaky / errati if (featureIsEnabled) e saldare alcune analisi wanky del codice statico in cima.

La soluzione è usare VCS correttamente . Dici maestro ramo quindi presumo tu stia usando Git. Quando si utilizza git, l'opzione migliore è utilizzare uno dei modelli di ramificazione standard (ad esempio GitFlow). Ciò che accomuna tutti i modelli di branching git testati e ampiamente usati è questo:

all commits to the master branch there is your problem. NEVER commit to the master branch. ONLY EVER merge to master from a branch that, prior to merging, has undergone a full test-cycle.

Se utilizzi per es. GitFlow puoi avere le tue branch caratteristiche pronte. Puoi metterli alla prova e assicurarti che rimangano integrati con il ramo principale. Quindi, quando qualcuno decide che la funzione deve diventare attiva, fai un altro ciclo di test di integrazione e di prova sul ramo della funzione, quindi uniscilo.
Quando una particolare caratteristica ha bisogno di un contrassegno di funzione (ad esempio per attivarsi solo per determinati clienti / su determinate impostazioni di sistema), dovrebbe essere parte della funzione. Prova questo flag come se fosse parte della funzione (proprio come when i click that button, the foo is frobnicated ).

Se, tuttavia, il tuo requisito è che tutte le funzionalità dovrebbero essere abilitate o disabilitate a piacimento, sei in GRANDI problemi. Questo è un problema per cui tutta la tua organizzazione deve essere pronta: con ogni nuova funzionalità la possibilità di stati del sistema viene moltiplicata per (almeno) 2. Hai casi di test per tutte le possibili combinazioni di funzioni abilitate? Sei pronto per l'enorme sovraccarico che incombe sullo sviluppo e sul rilascio? Le funzionalità dipendono l'una dall'altra e, in tal caso, sono presenti meccanismi per impedire l'abilitazione di una funzione mentre le sue dipendenze non lo sono?

Inoltre, se vuoi davvero seguire questa strada, dovresti prendere in considerazione un sistema modulare piuttosto che mettere tutto il codice in una cosa. Dai un'occhiata a come ad es. i moderni CMS gestiscono moduli / plug-in.

    
risposta data 29.07.2018 - 10:47
fonte
1

Penso che l'unico modo per fare ciò sia di effettuare test approfonditi per tutte le funzionalità esistenti, incluso testare cose come il contenuto dei menu per assicurarsi che non vengano mostrati nuovi elementi inattesi.

Se l'applicazione ha una GUI, allora alcuni test di integrazione che creano schermate della GUI e li confrontano con schermate di riferimento nel repository potrebbero renderlo un po 'più semplice. Ci sono strumenti che controllano la similarità se le immagini identiche binarie al 100% non sono fattibili. Più in generale è possibile confrontare qualsiasi output dell'applicazione con un esempio di riferimento.

Potresti quindi essere in grado di applicare una regola in base alla quale un nuovo commit di funzionalità non cambia nessuno dei file di test di integrazione esistenti, ma a essere sinceri penso che potresti farlo anche tramite la revisione del codice come da un sistema automatizzato .

Non penso che tu voglia utilizzare l'analisi del codice del codice di produzione come verifica per questo. Se lo facessi, potresti assicurarti che, a parte i rami del codice attivati dalle funzionalità, tutto sia uguale a prima, ma poi dovresti finire a dover duplicare qualsiasi codice che necessiti di refactoring o estensione per supportare la nuova funzione .

Ritarderebbe qualsiasi errore causato da errori fino al momento in cui la funzione è attiva. Ritardare i bug è una cosa molto brutta - se gli errori stanno per accadere, prima faranno meglio, poiché saranno molto più facili da risolvere. Infatti se stai usando le istruzioni per separare il nuovo codice dal vecchio codice che non stai realmente integrando, e potresti anche avere rami di funzionalità longevi nel VCS. È molto meglio lasciare che il nuovo codice funzioni subito e nascondere il risultato al livello dell'interfaccia utente.

Come ho suggerito nel mio commento, penso che sia necessario anche un terzo tipo di commit. I flag di funzionalità sono debito tecnologico se ne hai troppi in un'applicazione in una sola volta. Pertanto, devi eseguire commit che rimuovano i flag di funzionalità, passando attraverso il codebase e sostituendo un valore come Config.FeatureFlags.NewFeature456 con true o false , e quindi refactoring.

    
risposta data 29.07.2018 - 13:17
fonte
-1

Se la tua lingua supporta l'analisi di AST , sembra un problema relativamente semplice di analisi del codice. Per ogni file modificato, analizzarlo su AST prima e dopo la modifica, quindi discenderlo contemporaneamente, fino a quando non ottieni la differenza, saltando sopra le istruzioni "if (feature) {}".

Potrebbe avere alcune sfumature, ad esempio probabilmente vuoi consentire la dichiarazione di variabili con valori predefiniti in modo che possano estendersi su più istruzioni "if (feature) {}", ma nel complesso sembra fattibile

    
risposta data 29.07.2018 - 08:47
fonte

Leggi altre domande sui tag