Domanda

Ho visto molte domande che chiedevano "come" eseguire il test unitario in una lingua specifica, ma nessuna domanda che chiedeva "cosa", "perché" e "quando".

  • Che cos'è?
  • Cosa fa per me?
  • Perché dovrei usarlo?
  • Quando dovrei usarlo (anche quando no)?
  • Quali sono alcune trappole e malintesi comuni
È stato utile?

Soluzione

Il test unitario è, in parole povere, testare bit del tuo codice in isolamento con il codice di test.I vantaggi immediati che mi vengono in mente sono:

  • L'esecuzione dei test diventa automatizzabile e ripetibile
  • Puoi eseguire test a un livello molto più granulare rispetto ai test punta e clicca tramite una GUI

Tieni presente che se il tuo codice di test scrive su un file, apre una connessione al database o fa qualcosa sulla rete, è più appropriatamente classificato come test di integrazione.I test di integrazione sono una buona cosa, ma non devono essere confusi con i test unitari.Il codice del test unitario dovrebbe essere breve, dolce e veloce da eseguire.

Un altro modo di considerare i test unitari è scrivere prima i test.Questo è noto come Test-Driven Development (TDD in breve).Il TDD apporta ulteriori vantaggi:

  • Non scrivi un codice speculativo "Potrei averne bisogno in futuro", quanto basta per far passare i test
  • Il codice che hai scritto è sempre coperto da test
  • Scrivendo prima il test, sei costretto a pensare a come vuoi chiamare il codice, il che di solito migliora la progettazione del codice a lungo termine.

Se non stai eseguendo test unitari adesso, ti consiglio di iniziare.Procurati un buon libro, praticamente qualsiasi libro xUnit andrà bene perché i concetti sono molto trasferibili tra loro.

A volte scrivere test unitari può essere doloroso.Quando diventa così, prova a trovare qualcuno che ti aiuti e resisti alla tentazione di "scrivere semplicemente quel maledetto codice".Il test unitario è molto simile a lavare i piatti.Non è sempre piacevole, ma mantiene pulita la tua cucina metaforica e tu vuoi davvero che sia pulita.:)


Modificare:Mi viene in mente un malinteso, anche se non sono sicuro che sia così comune.Ho sentito un project manager dire che i test unitari hanno fatto sì che il team scrivesse tutto il codice due volte.Se sembra e sembra così, beh, stai sbagliando.La scrittura dei test di solito non solo accelera lo sviluppo, ma fornisce anche un comodo indicatore "ora ho finito" che altrimenti non avresti.

Altri suggerimenti

Non sono in disaccordo con Dan (anche se una scelta migliore potrebbe essere semplicemente non rispondere)...ma...

Il test unitario è il processo di scrittura del codice per testare il comportamento e la funzionalità del tuo sistema.

Ovviamente i test migliorano la qualità del tuo codice, ma questo è solo un vantaggio superficiale dei test unitari.I reali vantaggi sono:

  1. Semplifica la modifica dell'implementazione tecnica assicurandoti di non modificare il comportamento (refactoring).Il codice correttamente testato dall'unità può essere sottoposto a refactoring/pulizia in modo aggressivo con poche possibilità di rompere qualcosa senza accorgersene.
  2. Dai sicurezza agli sviluppatori quando aggiungono comportamenti o apportano correzioni.
  3. Documenta il tuo codice
  4. Indica le aree del tuo codice che sono strettamente accoppiate.È difficile eseguire test unitari di codice strettamente accoppiato
  5. Fornisci un mezzo per utilizzare la tua API e cercare le difficoltà nella fase iniziale
  6. Indica metodi e classi che non sono molto coesi

Dovresti eseguire il test unitario perché è nel tuo interesse fornire un prodotto manutenibile e di qualità al tuo cliente.

Ti suggerirei di usarlo per qualsiasi sistema, o parte di un sistema, che modelli il comportamento del mondo reale.In altre parole, è particolarmente adatto per lo sviluppo aziendale.Non lo userei per programmi usa e getta/di utilità.Non lo userei per parti di un sistema che sono problematiche da testare (l'interfaccia utente è un esempio comune, ma non è sempre così)

La trappola più grande è che gli sviluppatori testano un'unità troppo grande o considerano un metodo un'unità.Ciò è particolarmente vero se non capisci Inversione di controllo - nel qual caso i tuoi test unitari si trasformeranno sempre in test di integrazione end-to-end.Il test unitario dovrebbe testare i comportamenti individuali e la maggior parte dei metodi ha molti comportamenti.

Il più grande malinteso è che i programmatori non dovrebbero testare.Solo i programmatori cattivi o pigri ci credono.Il ragazzo che costruisce il tuo tetto non dovrebbe testarlo?Il medico che sostituisce una valvola cardiaca non dovrebbe testare la nuova valvola?Solo un programmatore può verificare che il suo codice faccia ciò che intendeva fare (il QA può testare i casi limite - come si comporta il codice quando gli viene detto di fare cose che il programmatore non intendeva, e il cliente può fare test di accettazione - fa il codice cosa ha pagato il cliente per farlo)

La differenza principale del test unitario, rispetto a "semplicemente aprire un nuovo progetto e testare questo codice specifico" è che lo è automatizzato, così ripetibile.

Se provi il tuo codice manualmente, potresti convincerti che il codice funziona perfettamente: nel suo stato attuale.Ma che ne dici di una settimana dopo, quando hai apportato una leggera modifica?Sei disposto a riprovarlo manualmente ogni volta nulla cambiamenti nel codice?Molto probabilmente no :-(

Ma se puoi esegui i tuoi test in qualsiasi momento, con un solo clic, esattamente allo stesso modo, in pochi secondi, Allora loro Volere mostrarti immediatamente ogni volta che qualcosa è rotto.E se integri anche gli unit test nel tuo processo di creazione automatizzato, ti avviseranno dei bug anche nei casi in cui una modifica apparentemente del tutto non correlata ha rotto qualcosa in una parte distante della base di codice - quando non ti verrebbe nemmeno in mente che ci sia la necessità di ripetere il test di quella particolare funzionalità.

Questo è il vantaggio principale dei test unitari rispetto ai test manuali.Ma aspetta, c'è di più:

  • test unitari abbreviare il ciclo di feedback sullo sviluppo drammaticamente:con un reparto di test separato potrebbero volerci settimane prima che tu sappia che c'è un bug nel tuo codice, a quel punto avrai già dimenticato gran parte del contesto, quindi potrebbero volerci ore per trovare e correggere il bug;OTOH con test unitari, il ciclo di feedback viene misurato in secondi e il processo di correzione dei bug è in genere sulla falsariga di un "oh merda, ho dimenticato di controllare quella condizione qui" :-)
  • test unitari in modo efficace documento (la tua comprensione del) comportamento del tuo codice
  • i test unitari ti costringono a rivalutare le tue scelte di progettazione, il che si traduce in design più semplice e pulito

I framework di unit test, a loro volta, semplificano la scrittura e l'esecuzione dei test.

Non mi hanno mai insegnato i test unitari all'università e mi ci è voluto un po' per "capirli".L'ho letto, ho detto "ah, giusto, test automatizzati, potrebbe essere interessante, immagino", e poi me ne sono dimenticato.

Ci è voluto un po' più di tempo prima che capissi davvero il punto:Diciamo che stai lavorando su un sistema di grandi dimensioni e scrivi un piccolo modulo.Si compila, lo metti alla prova, funziona alla grande, passi all'attività successiva.Nove mesi dopo e due versioni dopo qualcun altro apporta modifiche ad alcuni apparentemente parte non correlata del programma e interrompe il modulo.Peggio ancora, testano le modifiche e il codice funziona, ma non testano il modulo;diavolo, potrebbero anche non conoscere il tuo modulo esiste.

E ora hai un problema:il codice rotto è nel bagagliaio e nessuno lo sa nemmeno.Il caso migliore è che un tester interno lo trovi prima della spedizione, ma correggere il codice in una fase avanzata del gioco è costoso.E se nessun tester interno lo trova... beh, può diventare davvero molto costoso.

La soluzione sono i test unitari.Rileveranno problemi quando scrivi il codice, il che va bene, ma avresti potuto farlo a mano.Il vero vantaggio è che scopriranno i problemi nove mesi dopo, quando ora stai lavorando su un progetto completamente diverso, ma uno stagista estivo pensa che sembrerebbe più ordinato se quei parametri fossero in ordine alfabetico - e poi il test unitario hai scritto molto tempo fa fallisce e qualcuno lancia cose al tirocinante finché non cambia di nuovo l'ordine dei parametri. Quello è il "perché" dei test unitari.:-)

Intervenendo sui vantaggi filosofici dei test unitari e del TDD, ecco alcune delle osservazioni chiave della "lampadina" che mi hanno colpito durante i miei primi passi incerti sulla strada verso l'illuminazione del TDD (nessuna originale o necessariamente nuova)...

  1. TDD NON significa scrivere il doppio della quantità di codice.Il codice di test è in genere abbastanza rapido e indolore da scrivere ed è una parte fondamentale e critica del processo di progettazione.

  2. TDD ti aiuta a capire quando smettere di programmare!I tuoi test ti danno la certezza di aver fatto abbastanza per ora e di poter smettere di modificare e passare alla cosa successiva.

  3. I test e il codice lavorano insieme per ottenere un codice migliore.Il tuo codice potrebbe essere difettoso/bacato.Il tuo TEST potrebbe essere difettoso/difettoso.In TDD stai scommettendo sulle possibilità che ENTRAMBI siano cattivi / bacati siano piuttosto basse.Spesso è il test che deve essere corretto, ma è comunque un buon risultato.

  4. Il TDD aiuta a codificare la stitichezza.Hai presente quella sensazione di avere così tanto da fare che non sai a malapena da dove cominciare?È venerdì pomeriggio, se procrastini ancora per un paio d'ore...TDD ti consente di concretizzare molto rapidamente ciò che ritieni di dover fare e fa muovere rapidamente la tua codifica.Inoltre, come topi da laboratorio, penso che tutti noi rispondiamo a quella grande luce verde e lavoriamo di più per vederla di nuovo!

  5. Allo stesso modo, questi tipi di designer possono VEDERE a cosa stanno lavorando.Possono allontanarsi per una pausa con un succo/una sigaretta/un iphone e tornare davanti a un monitor che dà loro immediatamente un'indicazione visiva di dove sono arrivati.TDD ci dà qualcosa di simile.È più facile capire dove siamo arrivati ​​quando interviene la vita...

  6. Penso che sia stato Fowler a dire:"I test imperfetti, eseguiti frequentemente, sono molto meglio dei test perfetti che non vengono mai scritti".Interpreto questo come se mi concedesse il permesso di scrivere test dove penso che saranno più utili anche se il resto della mia copertura del codice è tristemente incompleta.

  7. TDD aiuta in tutti i modi sorprendenti su tutta la linea.Buoni test unitari possono aiutare a documentare cosa dovrebbe fare qualcosa, possono aiutarti a migrare il codice da un progetto a un altro e darti un'ingiustificata sensazione di superiorità rispetto ai tuoi colleghi che non hanno testato :)

Questa presentazione è un'eccellente introduzione a tutte le deliziose prove di bontà che comporta.

Vorrei raccomandare il libro xUnit Testing Patterns di Gerard Meszaros.È grande ma è un'ottima risorsa per i test unitari.Ecco un collegamento al suo sito Web in cui vengono discusse le basi dello unit test. http://xunitpatterns.com/XUnitBasics.html

Utilizzo i test unitari per risparmiare tempo.

Quando si crea la logica aziendale (o l'accesso ai dati), la funzionalità di test può spesso comportare la digitazione di elementi in molte schermate che potrebbero o non potrebbero essere ancora finite.Automatizzare questi test fa risparmiare tempo.

Per me i test unitari sono una sorta di cablaggio di prova modularizzato.Di solito c'è almeno un test per funzione pubblica.Scrivo test aggiuntivi per coprire vari comportamenti.

Tutti i casi speciali a cui hai pensato durante lo sviluppo del codice possono essere registrati nel codice negli unit test.Gli unit test diventano anche una fonte di esempi su come utilizzare il codice.

È molto più veloce per me scoprire che il mio nuovo codice rompe qualcosa nei miei test unitari, quindi controllare il codice e chiedere a qualche sviluppatore front-end di trovare un problema.

Per i test di accesso ai dati provo a scrivere test che non subiscano modifiche o che si ripuliscano da soli.

I test unitari non saranno in grado di risolvere tutti i requisiti di test.Saranno in grado di risparmiare tempo di sviluppo e testare le parti principali dell'applicazione.

Questa è la mia opinione al riguardo.Direi che il test unitario è la pratica di scrivere test software per verificare che il tuo software reale faccia ciò per cui è destinato.Questo è iniziato con jUnità nel mondo Java ed è diventata una best practice anche in PHP Test semplice E phpUnit.È una pratica fondamentale di Extreme Programming e ti aiuta ad essere sicuro che il tuo software funzioni ancora come previsto dopo la modifica.Se disponi di una copertura di test sufficiente, puoi eseguire importanti refactoring, correggere bug o aggiungere funzionalità rapidamente con molta meno paura di introdurre altri problemi.

È più efficace quando tutti i test unitari possono essere eseguiti automaticamente.

Il test unitario è generalmente associato allo sviluppo OO.L'idea di base è creare uno script che imposti l'ambiente per il tuo codice e poi lo eserciti;scrivi asserzioni, specifichi l'output previsto che dovresti ricevere e quindi esegui lo script di test utilizzando un framework come quelli menzionati sopra.

Il framework eseguirà tutti i test rispetto al tuo codice e quindi riporterà il successo o il fallimento di ciascun test.phpUnit viene eseguito dalla riga di comando di Linux per impostazione predefinita, sebbene siano disponibili interfacce HTTP.SimpleTest è basato sul web per natura ed è molto più facile da installare e utilizzare, IMO.In combinazione con xDebug, phpUnit può fornirti statistiche automatizzate per la copertura del codice che alcune persone trovano molto utili.

Alcuni team scrivono hook dal loro repository subversion in modo che gli unit test vengano eseguiti automaticamente ogni volta che si apportano modifiche.

È buona norma mantenere i test unitari nello stesso repository dell'applicazione.

Piace alle biblioteche NUnità, xUnità O JUnit sono obbligatori solo se vuoi sviluppare i tuoi progetti utilizzando il file TDD approccio reso popolare da Kent Beck:

Puoi leggere Introduzione al Test Driven Development (TDD) o il libro di Kent Beck Sviluppo guidato dai test:Per esempio.

Quindi, se vuoi essere sicuro che i tuoi test coprano una parte "buona" del tuo codice, puoi utilizzare software come NCopertura, JCopertina, ParteCover o qualunque cosa.Ti diranno la percentuale di copertura del tuo codice.A seconda di quanto sei esperto in TDD, saprai se lo hai praticato abbastanza bene :)

Il test unitario è il test di un'unità di codice (ad es.una singola funzione) senza la necessità dell'infrastruttura su cui si basa l'unità di codice.cioè.testarlo in isolamento.

Se, ad esempio, la funzione che stai testando si connette a un database ed esegue un aggiornamento, in uno unit test potresti non voler eseguire tale aggiornamento.Lo faresti se fosse un test di integrazione, ma in questo caso non lo è.

Pertanto un test unitario eserciterebbe la funzionalità racchiusa nella "funzione" che stai testando senza effetti collaterali dell'aggiornamento del database.

Supponiamo che la tua funzione abbia recuperato alcuni numeri da un database e quindi abbia eseguito un calcolo della deviazione standard.Cosa stai cercando di testare qui?Che la deviazione standard sia calcolata correttamente o che i dati vengano restituiti dal database?

In un test unitario vuoi solo verificare che la deviazione standard sia calcolata correttamente.In un test di integrazione si desidera testare il calcolo della deviazione standard e il recupero del database.

Il test unitario riguarda la scrittura di codice che verifica il codice dell'applicazione.

IL Unità parte del nome riguarda l'intenzione di testare piccole unità di codice (un metodo per esempio) alla volta.

xUnit è lì per aiutare con questi test: sono framework che aiutano in questo.Parte di ciò sono i test runner automatizzati che ti dicono quali test falliscono e quali passano.

Dispongono inoltre di strutture per impostare in anticipo il codice comune necessario in ciascun test e rimuoverlo al termine di tutti i test.

Puoi eseguire un test per verificare che sia stata lanciata un'eccezione prevista, senza dover scrivere tu stesso l'intero blocco try catch.

Penso che il punto che non capisci è che i framework di unit test come NUnit (e simili) ti aiuteranno in automatizzando test di piccole e medie dimensioni.Di solito è possibile eseguire i test in una GUI (è il caso di NUnità, ad esempio) semplicemente facendo clic su un pulsante e poi, si spera, vedere la barra di avanzamento rimanere verde.Se diventa rosso, il framework mostra quale test ha fallito e cosa è andato storto esattamente.In un normale unit test si utilizzano spesso asserzioni, ad es. Assert.AreEqual(expectedValue, actualValue, "some description") - quindi se i due valori non sono uguali vedrai un errore che dice "qualche descrizione:previsto <expectedValue> ma era <actualValue>".

Quindi, in conclusione, i test unitari renderanno i test più veloci e molto più comodi per gli sviluppatori.Puoi eseguire tutti gli unit test prima di eseguire il commit del nuovo codice in modo da non interrompere il processo di compilazione di altri sviluppatori sullo stesso progetto.

Utilizzo Testimone.Tutto quello che devi sapere è proprio lì :)

Il test unitario è una pratica per assicurarsi che la funzione o il modulo che si intende implementare si comporterà come previsto (requisiti) e anche per assicurarsi come si comporta in scenari come condizioni al contorno e input non validi.

xUnità, NUnità, mbUnit, eccetera.sono strumenti che ti aiutano nella scrittura dei test.

Test Driven Development ha in qualche modo preso il sopravvento sul termine Unit Test.Da veterano ne menzionerò la definizione più generica.

Unit Test significa anche testare un singolo componente in un sistema più grande.Questo singolo componente potrebbe essere una DLL, un exe, una libreria di classi, ecc.Potrebbe anche trattarsi di un singolo sistema in un'applicazione multisistema.Quindi alla fine Unit Test finisce per essere il test di qualunque cosa tu voglia chiamare un singolo pezzo di un sistema più ampio.

Passerai quindi al test integrato o di sistema testando il modo in cui tutti i componenti funzionano insieme.

Prima di tutto, sia che si parli di unit test o di qualsiasi altro tipo di test automatizzato (integrazione, carico, test dell'interfaccia utente, ecc.), la differenza fondamentale rispetto a ciò che suggerisci è che è automatizzato, ripetibile e non richiede risorse umane da consumare (= nessuno deve eseguire i test, di solito vengono eseguiti premendo un pulsante).

Sono andato a una presentazione sui test unitari al FoxForward 2007 e mi è stato detto di non testare mai nulla che funzioni con i dati.Dopotutto, se esegui test su dati in tempo reale, i risultati sono imprevedibili e se non esegui test su dati in tempo reale, in realtà non stai testando il codice che hai scritto.Sfortunatamente, questa è la maggior parte della codifica che faccio in questi giorni.:-)

Recentemente ho provato a TDD mentre stavo scrivendo una routine per salvare e ripristinare le impostazioni.Innanzitutto, ho verificato di poter creare l'oggetto di archiviazione.Quindi, che aveva il metodo di cui avevo bisogno per chiamare.Quindi, potrei chiamarlo così.Quindi, potrei passargli i parametri.Quindi, potrei passargli parametri specifici.E così via, finché non ho finalmente verificato che avrebbe salvato l'impostazione specificata, permettendomi di modificarla e quindi ripristinarla, per diverse sintassi diverse.

Non sono arrivato alla fine, perché avevo bisogno della routine, dannazione, ma è stato un buon esercizio.

Cosa fai se ti viene dato un mucchio di schifezze e ti sembra di essere bloccato in un perpetuo stato di pulizia che sai che con l'aggiunta di qualsiasi nuova funzionalità o codice può rompere il set attuale perché il software attuale è come una casa di carte?

Come possiamo quindi eseguire test unitari?

Inizi in piccolo.Il progetto in cui sono appena entrato non prevedeva test unitari fino a pochi mesi fa.Quando la copertura era così bassa, sceglievamo semplicemente un file che non aveva copertura e facevamo clic su "aggiungi test".

In questo momento siamo a oltre il 40% e siamo riusciti a raccogliere la maggior parte dei frutti a portata di mano.

(La parte migliore è che anche a questo basso livello di copertura, ci siamo già imbattuti in molte istanze del codice che facevano la cosa sbagliata e i test l'hanno rilevato.Questo è un enorme motivatore per spingere le persone ad aggiungere più test.)

Questo risponde al motivo per cui dovresti eseguire test unitari.


I 3 video seguenti riguardano i test unitari in Javascript, ma i principi generali si applicano alla maggior parte delle lingue.

Test unitario:I minuti adesso risparmieranno ore dopo - Eric Mann - https://www.youtube.com/watch?v=_UmmaPe8Bzc

JS Unit Testing (molto buono) - https://www.youtube.com/watch?v=-IYqgx8JxlU

Scrittura di JavaScript verificabile - https://www.youtube.com/watch?v=OzjogCFO4Zo


Ora sto appena imparando l'argomento, quindi potrei non essere corretto al 100% e c'è di più rispetto a quello che sto descrivendo qui, ma la mia comprensione di base del test unitario è che scrivi del codice di test (che viene tenuto separato dal tuo codice principale) che chiama una funzione nel codice principale con l'input (argomenti) richiesto dalla funzione e il codice quindi controlla se ottiene un valore restituito valido.Se ottiene un valore valido, il framework di test unitario che stai utilizzando per eseguire i test mostra una luce verde (tutto ok) se il valore non è valido ottieni una luce rossa e quindi puoi risolvere il problema immediatamente prima di te rilascia il nuovo codice in produzione, senza testarlo potresti non aver rilevato l'errore.

Quindi scrivi test per il tuo codice corrente e crei il codice in modo che superi il test.Mesi dopo tu o qualcun altro dovete modificare la funzione nel vostro codice principale, perché prima avevi già scritto il codice di test per quella funzione, ora esegui di nuovo e il test potrebbe fallire perché il programmatore ha introdotto un errore logico nella funzione o restituisce qualcosa di completamente diverso da quello che quella funzione dovrebbe restituire.Anche in questo caso, senza il test in atto, l'errore potrebbe essere difficile da rintracciare poiché potrebbe influenzare anche altro codice e passare inosservato.


Anche il fatto di avere un programma per computer che esegue il tuo codice e lo testa invece di farlo manualmente nel browser pagina per pagina fa risparmiare tempo (test unitario per javascript).Diciamo che modifichi una funzione utilizzata da alcuni script su una pagina Web e funziona perfettamente per il suo nuovo scopo previsto.Ma diciamo anche, per amor di discussione, che c'è un'altra funzione che hai da qualche altra parte nel tuo codice che dipende da quella funzione appena modificata affinché funzioni correttamente.Questa funzione dipendente potrebbe ora smettere di funzionare a causa delle modifiche apportate alla prima funzione, tuttavia senza test eseguiti automaticamente dal tuo computer non noterai che c'è un problema con quella funzione finché non viene effettivamente eseguita e dovrai navigare manualmente verso una pagina web che include lo script che esegue la funzione dipendente, solo allora noterai che c'è un bug a causa della modifica che hai apportato alla prima funzione.

Per ribadire, l'esecuzione di test durante lo sviluppo dell'applicazione consentirà di individuare questo tipo di problemi durante la codifica.Non avendo i test in atto dovresti passare manualmente attraverso l'intera applicazione e anche in questo caso può essere difficile individuare il bug, ingenuamente lo mandi in produzione e dopo un po' un utente gentile ti invia una segnalazione di bug (che non sarà buono come i tuoi messaggi di errore in un framework di test).


È abbastanza confuso quando senti parlare per la prima volta dell'argomento e pensi a te stesso, non sto già testando il mio codice?E il codice che hai scritto funziona già come dovrebbe, "perché ho bisogno di un altro framework?"...Sì, stai già testando il tuo codice, ma un computer è più bravo a farlo.Devi solo scrivere test sufficientemente buoni per una funzione/unità di codice una volta e il resto viene curato dalla potente CPU invece di dover controllare manualmente che tutto il tuo codice funzioni ancora quando apporti una modifica a il tuo codice.

Inoltre, non è necessario testare l'unità del codice se non lo si desidera, ma si ripaga poiché il progetto/base di codice inizia a ingrandirsi man mano che aumentano le possibilità di introdurre bug.

Il test unitario e il TDD in generale ti consentono di avere cicli di feedback più brevi sul software che stai scrivendo.Invece di avere una lunga fase di test alla fine dell'implementazione, testi in modo incrementale tutto ciò che scrivi.Ciò aumenta moltissimo la qualità del codice, come puoi vedere immediatamente, dove potresti avere dei bug.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top