Le librerie client di Cloud per Rust forniscono un modo per eseguire lo stub delle implementazioni client reali, in modo da poter inserire un mock per i test. Puoi utilizzare i mock per scrivere test delle unità controllati e affidabili che non effettuano chiamate di rete o non comportano addebiti.
In questo documento vengono trattati i seguenti argomenti:
- Come scrivere interfacce testabili utilizzando il client
Storagedi Cloud Storage. - Come simulare le operazioni di lettura.
- Come simulare le operazioni di scrittura.
- Perché il design del client
Storageè diverso da quello di altri client Google Cloud.
Dipendenze
Aggiungi la libreria client di Cloud Storage al file Cargo.toml:
cargo add google-cloud-storage
Per compilare ed eseguire i test delle unità in questo documento, aggiungi le seguenti dipendenze di sviluppo:
cargo add --dev anyhow bytes mockall
cargo add --dev tokio --features macros,rt-multi-thread
Scrivi interfacce testabili
Se non esegui test delle unità del codice di archiviazione, puoi scrivere interfacce direttamente in termini di Storage, il cui parametro del tipo di stub predefinito è l'implementazione di produzione del client:
Per testare il codice con un client fittizio, scrivi le interfacce in termini di un parametro di tipo generico T vincolato da gcs::stub::Storage + 'static:
Operazioni di lettura fittizie
Per simulare le richieste read_object, completa i seguenti passaggi:
Scrivi una funzione dell'applicazione che accetti un client
&Storage<T>generico. Ad esempio, la seguente funzione scarica un oggetto e conta quanti caratteri di nuova riga contiene:Crea una funzione helper che costruisce un flusso di byte
ReadObjectResponsefittizio passando un payload aReadObjectResponse::from_source. Questo metodo accetta gli stessi tipi di payload diStorage::write_object:Definisci una struttura fittizia che implementa
gcs::stub::Storage. Questo documento utilizza il cratemockall, anche se puoi utilizzare un framework di simulazione diverso nei test:Scrivi un test delle unità che imposti le aspettative sul mock, costruisca un client utilizzando
Storage::from_stube chiamicount_newlines:
Operazioni di scrittura fittizie
Per simulare le richieste write_object, completa i seguenti passaggi:
Scrivi una funzione dell'applicazione che carica un oggetto utilizzando un client
&Storage<T>generico:Utilizzando la struttura
MockStoragedefinita nella sezione precedente, scrivi un test delle unità che configura le aspettative sul mock, costruisce un client utilizzandoStorage::from_stube chiamaupload:
Dettagli sulle aspettative
Poiché la funzione upload chiama send_unbuffered, imposta l'aspettativa sul metodo expect_write_object_unbuffered corrispondente:
La macro mockall::mock! tratta ogni istanza generica come un metodo distinto. Specifica il tipo di payload concreto, Payload<BytesSource>, nella firma della chiusura in modo che il compilatore possa corrispondere all'aspettativa del metodo:
Motivazione del design
Le sezioni seguenti spiegano perché il client Storage utilizza un parametro di tipo generico per il relativo stub anziché l'invio dinamico.
Altri client
La maggior parte dei client, come StorageControl, contiene internamente un'implementazione compatibile con dyn del proprio tratto stub con conteggio dei riferimenti (Arc). Utilizzano l'invio dinamico per inoltrare le richieste dal client allo stub sottostante, che può essere l'implementazione di produzione o un mock.
Poiché questi client utilizzano l'invio dinamico, il compilatore non deve risolvere il tipo di stub concreto in tempo di compilazione e le strutture client non hanno bisogno di un parametro di tipo generico per il loro stub.
Il client Storage
In Rust, un tratto compatibile con dyn non può avere metodi generici o restituire valori impl Future non unboxed:
- I metodi
write_object_bufferedewrite_object_unbufferedsono generici per il tipo di origine del payload. - I metodi del tratto
gcs::stub::Storagerestituiscono direttamenteimpl Futureanziché eseguire il boxing del future restituito.
L'utilizzo del dynamic dispatch per il client Storage richiederebbe il boxing dei payload e dei future su ogni chiamata, aggiungendo allocazioni heap e overhead del dynamic dispatch sul percorso dei dati. Per evitare questo overhead, il client Storage utilizza invece un parametro di tipo per un'implementazione concreta del tratto gcs::stub::Storage.
Codice dell'applicazione e suite di test completi
Il seguente codice combina le funzioni dell'applicazione e i test delle unità in un esempio completo:
Esegui cargo test per eseguire test_count_lines e test_upload:
cargo test