Ciao, Habr!
Mi chiamo Maxim Ponomarenko e sono uno sviluppatore in Sportmaster. Ho 10 anni di esperienza nel settore IT. Ho iniziato la mia carriera nel campo del testing manuale, poi mi sono spostato nello sviluppo di database. Negli ultimi 4 anni, accumulando le conoscenze acquisite nel testing e nello sviluppo, mi occupo dell'automazione del testing a livello di DBMS.
Faccio parte del team di Sportmaster da poco più di un anno e in uno dei grandi progetti mi occupo dello sviluppo del testing automatico. Ad aprile, insieme ai ragazzi di Sportmaster Lab, abbiamo partecipato a una conferenza a Krasnodar, il mio intervento si intitolava “Unit test nel DBMS”, e ora voglio condividerlo con voi. Ci sarà molta carne al fuoco, quindi ho deciso di suddividere l'intervento in due post. Nel primo parleremo dei test automatici e del testing in generale, mentre nel secondo ci soffermeremo più nel dettaglio sul nostro sistema di unit testing e sui risultati ottenuti.
Iniziamo con un po' di noiosa teoria. Cos'è il testing automatico? È un tipo di testing che viene effettuato tramite strumenti software e nell'IT moderno viene utilizzato sempre più frequentemente nello sviluppo di software. Questo è legato al fatto che le aziende crescono, crescono anche i loro sistemi informatici e di conseguenza aumenta il numero di funzionalità da testare. Effettuare testing manuale diventa sempre più costoso e complicato.
Ho lavorato in una grande azienda, i cui rilasci avvengono ogni due mesi. Durante il primo mese, un team di dieci tester controllava manualmente le funzionalità. Grazie all'implementazione dell'automazione con un piccolo team di sviluppatori, siamo riusciti a ridurre il tempo di testing a due settimane in un anno e mezzo. Non solo abbiamo aumentato la velocità del testing, ma abbiamo anche migliorato la sua qualità. I test automatici vengono eseguiti regolarmente e compiono sempre tutte le verifiche programmate, escludendo così il fattore umano.
Nel moderno settore IT è caratteristico che da uno sviluppatore non si richieda solo di scrivere il codice del prodotto, ma anche di scrivere unit test che verifichino quel codice.
Ma cosa fare se il vostro sistema si basa principalmente sulla logica del server? Non esiste una soluzione universale e best practices sul mercato. Di solito, le aziende risolvono questo problema creando il proprio sistema di test personalizzato. Un sistema di test automatizzato personalizzato è stato creato nel nostro progetto, e di questo parlerò nella mia presentazione.

Testiamo la fedeltà
Iniziamo a parlare del progetto in cui abbiamo implementato il sistema di test automatizzato. Il nostro progetto è un sistema di fedeltà di Sportmaster (tra l'altro, ne abbiamo già parlato in ).
Se la vostra azienda è abbastanza grande, il vostro sistema di fedeltà avrà tre caratteristiche standard:
- Il vostro sistema sarà ad alta capacità di carico
- Il vostro sistema conterrà processi computazionali complessi
- Il vostro sistema sarà attivamente sviluppato.
Procediamo con ordine… Complessivamente, se consideriamo tutti i marchi di Sportmaster, abbiamo più di 1000 negozi sul territorio di Russia, Ucraina, Cina, Kazakistan e Bielorussia. In questi negozi si effettuano circa 300.000 acquisti ogni giorno. Questo significa che ogni secondo nel nostro sistema entra da 3 a 4 scontrini. Naturalmente, il nostro sistema di fedeltà è ad alta capacità di carico. E poiché è usato attivamente, dobbiamo fornire i più alti standard di qualità, poiché qualsiasi errore nel software comporta grandi perdite economiche, reputazionali e altro.
Contemporaneamente, in Sportmaster operano più di cento diverse promozioni. Le promozioni sono le più varie: ci sono quelle sui prodotti, quelle legate ai giorni della settimana, quelle collegate a negozi specifici, ci sono promozioni sul valore dello scontrino e sul numero di prodotti. Insomma, non è affatto banale. I clienti hanno bonus, ci sono codici promozionali utilizzati durante gli acquisti. Tutto ciò porta al fatto che il calcolo di qualsiasi ordine è un compito piuttosto complesso.
L'algoritmo che gestisce l'elaborazione degli ordini è davvero terribile e complesso. Qualsiasi modifica a questo algoritmo è un rischio piuttosto elevato. Anche le più insignificanti variazioni apparenti possono portare a effetti abbastanza imprevedibili. Ecco perché tali processi computazionali complessi, specialmente quelli che implementano funzionalità critiche, sono i migliori candidati per l'automazione. Controllare manualmente decine di casi simili richiede molto tempo. E poiché il punto di ingresso nel processo rimane invariato, descrivendolo una volta è possibile generare rapidamente test automatici e avere fiducia nel funzionamento della funzionalità.
Poiché il nostro sistema viene utilizzato attivamente, le aziende si aspettano da voi qualcosa di nuovo, di essere al passo con i tempi e di essere orientati al cliente. Nel nostro sistema di fidelizzazione, le versioni vengono rilasciate ogni due mesi. Quindi, ogni due mesi dobbiamo eseguire un regresso completo dell'intero sistema. Inoltre, come in qualsiasi IT moderno, lo sviluppo non passa immediatamente dal programmatore alla produzione. Nasce nel contesto dello sviluppatore, poi passa successivamente attraverso l'ambiente di test, il rilascio, l'accettazione e solo dopo arriva in produzione. Almeno negli ambienti di test e rilascio, è necessario eseguire un regresso completo dell'intero sistema.
Le proprietà descritte sono standard per praticamente qualsiasi sistema di fidelizzazione. Parliamo ora delle peculiarità del nostro progetto.
Dal punto di vista tecnologico, il 90% della logica del nostro sistema di fidelizzazione è server-side e realizzata su Oracle. C'è un client basato su Delphi che svolge la funzione di amministratore APM. Sono disponibili dei web service per applicazioni esterne (ad esempio, il sito web). Pertanto, è logico che, se sviluppiamo un sistema di test automatizzati, lo faremo su Oracle.
Il sistema di fidelizzazione di Sportmaster esiste da oltre 7 anni ed è stato sviluppato da singoli programmatori... Il numero medio di sviluppatori nel nostro progetto in questi 7 anni è stato di 3-4 persone. Ma nell'ultimo anno il nostro team è cresciuto notevolmente, e ora 10 persone lavorano al progetto. Ciò significa che nel progetto arrivano persone che non conoscono le attività tipiche, i processi, l'architettura. E c'è un rischio maggiore che ci possano sfuggire degli errori.
Il progetto è caratterizzato dall'assenza di tester dedicati come unità statutarie. Ci sono indubbiamente test, ma sono condotti da analisti, oltre alle loro altre principali responsabilità: comunicare con i clienti aziendali, gli utenti, elaborare i requisiti per il sistema e così via... Nonostante i test vengano effettuati in modo molto qualitativo (è opportuno menzionarlo, poiché potrebbe capitare che questo report venga visto da qualche analista), l'efficacia della specializzazione e della concentrazione su un unico compito non è mai stata smentita.
Tenendo conto di quanto detto, per migliorare la qualità del prodotto fornito e ridurre i tempi di sviluppo, l'idea di automatizzare i test nel progetto sembra molto logica. In diverse fasi dell'esistenza del sistema di fidelizzazione, singoli sviluppatori hanno fatto sforzi per coprire il proprio codice con test unitari. In generale, si è trattato di un processo piuttosto frammentato, dove ciascuno ha utilizzato la propria architettura e metodi. I risultati finali per i test unitari erano comuni: i test venivano sviluppati, utilizzati per un certo periodo, archiviati in una repository di versioni, ma a un certo punto smettevano di essere eseguiti e venivano dimenticati. Questo accadeva principalmente perché i test erano più legati a chi li aveva eseguiti piuttosto che al progetto.
A darci una mano arriva utPLSQL

Sai qualcosa su Steven Feuerstein?
Questo è un esperto che ha dedicato gran parte della sua carriera a lavorare con Oracle e PL/SQL, scrivendo un numero significativo di opere su questo argomento. Uno dei suoi libri più noti si intitola: «Oracle PL/SQL. Per professionisti». È a Stephen che si deve lo sviluppo della soluzione utPLSQL, che sta per Unit Testing framework per Oracle PL/SQL. La soluzione utPLSQL è stata creata nel 2016, ma continua a essere attivamente sviluppata con nuove versioni. Al momento della relazione, l'ultima versione risale al 24 marzo 2019.
Che cos'è allora? È un progetto open source a sé stante. Occupando un paio di megabyte, inclusi esempi e documentazione, rappresenta fisicamente uno schema separato nel database ORACLE con un insieme di pacchetti e tabelle per organizzare il unit testing. L'installazione richiede solo pochi secondi. La caratteristica distintiva di utPLSQL è la sua semplicità d'uso.
In termini generali, utPLSQL è un meccanismo per eseguire unit test, dove per unit test si intendono le normali procedure di pacchetti Oracle, organizzate in base a determinate regole. Oltre all'esecuzione, utPLSQL conserva un registro di tutte le esecuzioni di test e ha anche un sistema interno di reportistica.
Vediamo un esempio di come appare il codice di un unit test implementato secondo questo metodo.

Quindi, sullo schermo abbiamo il codice di una tipica specifica di pacchetto con unit test. Quali sono i requisiti obbligatori? Il pacchetto deve avere il prefisso «utp_». Lo stesso prefisso deve avere tutte le procedure di test. Nel pacchetto devono essere presenti due procedure standard: «utp_setup» e «utp_teardown». La prima procedura viene chiamata prima di ogni unit test, la seconda — dopo l'esecuzione.
«utp_setup», in genere, prepara il nostro sistema per l'esecuzione dell'unit test, ad esempio, creando dati di test. «utp_teardown» — al contrario, ripristina tutto alle impostazioni iniziali e annulla i risultati dell'esecuzione.
Ecco un esempio del più semplice test unitario, che verifica la normalizzazione del numero di telefono fornito dal cliente al formato standard della nostra sistema di fidelizzazione. Non esistono standard obbligatori su come scrivere procedure con test unitari. Di solito viene chiamato un metodo del sistema testato e il risultato restituito da questo metodo viene confrontato con quello atteso. È importante che il confronto tra il risultato atteso e quello ottenuto avvenga attraverso i metodi standard di utPLSQL.
In un test unitario, possono esserci un numero qualsiasi di controlli. Come si può vedere dall'esempio, facciamo quattro chiamate successive al metodo testato per la normalizzazione del numero di telefono e dopo ciascuna chiamata valutiamo il risultato. Quando si sviluppa un test unitario, è necessario tenere presente che ci sono controlli che non influenzano in alcun modo il sistema, mentre dopo alcuni è necessario tornare allo stato iniziale del sistema.
Ad esempio, nel test unitario presentato formattiamo semplicemente il numero di telefono in ingresso, il che non influisce in alcun modo sul sistema di fidelizzazione.
E se scriviamo test unitari per il metodo di creazione di un nuovo cliente, dopo ogni controllo verrà creato un nuovo cliente nel sistema, il che può influenzare l'esecuzione dei test successivi.

Ecco come vengono eseguiti i test unitari. Sono ammesse due modalità di esecuzione: esecuzione di tutti i test unitari di un pacchetto specifico o esecuzione di un test unitario specifico in un pacchetto specifico.

Ecco come appare l'esempio del sistema di reportistica interna. In base ai risultati del test unitario, utPLSQL genera un piccolo rapporto. In questo vediamo il risultato di ciascun controllo specifico e il risultato complessivo dell'esecuzione del test unitario.
6 regole per i test automatici
Prima di iniziare a creare un nuovo sistema di test automatizzati per il sistema di fidelizzazione, abbiamo definito insieme alla direzione i principi a cui i nostri futuri test automatici dovranno aderire.

- I test automatici devono essere efficaci e portare vantaggi. Abbiamo sviluppatori straordinari, di cui è necessario parlare, poiché qualcuno di loro sicuramente leggerà questa relazione, e scrivono codice eccellente. Ma anche il loro codice notevole non è perfetto e ha, ha e avrà errori. I test automatici devono essere in grado di individuare questi errori. Se non è così, allora stiamo scrivendo test automatici scadenti, oppure siamo entrati in un'area morta, che in linea di principio non viene elaborata. In entrambi i casi stiamo facendo qualcosa di sbagliato, e il nostro approccio è semplicemente privo di senso.
- I test automatici devono essere utilizzati. È insensato spendere un sacco di tempo e sforzi per scrivere un prodotto software, assemblare il suo repository e dimenticarlo. I test devono essere eseguiti, e devono essere eseguiti il più frequentemente possibile.
- I test automatici devono funzionare in modo stabile. Indipendentemente dall'ora del giorno, dallo stand di esecuzione e da altre impostazioni del sistema, i lanci dei test devono portare sempre allo stesso risultato. Di solito, ciò è garantito dal fatto che i test automatici lavorano con dati di test speciali con impostazioni di sistema definite.
- I test automatici devono operare con una velocità accettabile per il tuo progetto. Questo tempo è determinato individualmente per ogni sistema. Alcuni possono permettersi di lavorare per l'intera giornata, mentre per altri è critico rimanere nei secondi. Quali standard di velocità abbiamo raggiunto nel nostro progetto, ne parlerò più avanti.
- Lo sviluppo dei test automatici deve essere flessibile. È indesiderabile rinunciare a verificare un qualche funzionalità semplicemente perché non l'abbiamo mai fatto o per altre convinzioni. utPLSQL non impone limiti allo sviluppo, e Oracle in linea di principio consente di realizzare le cose più diverse. La maggior parte dei problemi ha una soluzione, la questione è solo di tempo e sforzi spesi.
- Distribuibilità. Abbiamo diversi stand dove è necessario eseguire i test. In ciascuno degli stand può essere aggiornato un dump con i dati in qualsiasi momento. È necessario gestire il progetto con test automatici in modo da poter effettuare senza problemi la sua installazione totale o parziale.
E nel secondo post tra un paio di giorni parlerò di cosa abbiamo fatto e quali risultati abbiamo raggiunto.
Fonte: habr.com
