Ho iniziato a lavorare come codificatore per circa 2 anni, ma sto scrivendo i miei primi "veri" test per un'applicazione non banale. Ho cercato di seguire le best practice che ho raccolto da internet qua e là, ma vorrei un feedback sul fatto che sto andando nella giusta direzione con quello che sto facendo e che cosa posso fare per correggere / migliorare il mio processo.
L'applicazione è un'API headless che vedrà pubblico (alias i client che desiderano integrarsi con la nostra API, non completamente pubblico) in pochi mesi.
Dall'alto verso il basso, lo stack e i livelli hanno questo aspetto:
- API RESTful (JSON)
- Autenticazione Oauth 2.0
- (Principalmente) controller CRUD (PHP, Laravel 5 )
- Doctrine ORM per DAL
- DB MySQL
Volevo progettare i miei test per essere il più semplice ma accurato possibile. Tuttavia non ho l'eternità e un giorno per scrivere test davvero fondamentali (test unitari, immagino) per tutti i controller e tutte le logiche di business, quindi ho deciso di approfittare di laravel ha creato mocking per i percorsi e testa tutti gli endpoint per la nostra API.
La mia linea di pensiero è che, dal momento che abbiamo strutture dati e formati standard per richiesta / risposta (JSON, schemi json definiti per oggetti, ecc.) potrei emulare richieste sapendo quale dovrebbe essere la risposta e confrontare le due.
EX. GET api/user/1
dovrebbe restituire user 1
come un oggetto json che posso confrontare per uguaglianza con il json serializzato che l'oggetto reale mi dà.
Quindi il test attuale è simile a questo (usando PHPunit):
- All'avvio dell'applicazione Laravel imposta l'ambiente dell'app su "testing" che cambia la connessione DB predefinita a un file SQLite
- All'avvio di PHPunit Doctrine ottiene i metadati del modello e crea le tabelle per il mio dominio nel DB, alcuni script aggiuntivi per cose extra-dominio (tabelle oauth) creano anche quelli
- Alice , un generatore di oggetti per la dottrina, crea un insieme decentemente diversificato di entità di dominio con dati casuali da Faker e idrata il DB SQLite. Tutte le entità create vengono restituite e le memorizzo in una variabile globale per uso futuro.
- Realizzo una copia del DB idratato e intatto da utilizzare nei test che coinvolgono le operazioni di scrittura in modo da poter ripristinare il db dopo ogni test.
- I client Oauth vengono generati per gli utenti con ruoli diversi, quindi posso testare oauth scope e permessi tra utenti diversi per ogni test
- Uso Laravel's route mocking per chiamare ciascun endpoint dell'API e
- Per i test di sola lettura (GET) uso la forma serializzata di json degli oggetti memorizzati in precedenza (fase 3) per testare l'uguaglianza delle risposte,
- Per i test di scrittura costruisco richieste dal nostro oggetto json schemi, quindi costruisco un oggetto reale che dovrebbe uguagliarlo, formulare la richiesta e quindi controllare la risposta per l'uguaglianza con la forma serializzata dell'oggetto (come il punto 7). Dopo ciascun test di scrittura, il DB viene sovrascritto con il DB idratato originale del passaggio 4 per il test successivo.
Quindi questo è il senso. L'utilizzo di questo approccio mi ha dato prestazioni fantastiche: eseguire 26 test con 87 asserzioni richiede ~ 12 secondi.
Le mie domande / dubbi
- Non sto prendendo in giro niente. Mi sento come se stavo facendo qualcosa di sbagliato a causa di questo, ma allo stesso tempo sto fornendo un ambiente "reale" per l'intera applicazione, quindi niente sembra che debba essere deriso. Va bene?
- Sto provando a fare troppo con ogni test? Ho letto articoli che mettono in guardia dall'avere troppe dipendenze in un test perché rende il test fragile e meno efficace, ma tutte le "dipendenze" nei miei test sono codice reale, quindi se un test si interrompe significa il mio codice reale è rotto, cosa che vorrei sapere.
Cos'altro puoi dirmi? Suggerimenti? Come posso migliorare questo? Grazie!