Las bibliotecas cliente de Cloud para Rust proporcionan una forma de crear stub de implementaciones de clientes reales para que puedas insertar una simulación para las pruebas. Puedes usar simulaciones para escribir pruebas de unidades controladas y confiables que no realicen llamadas de red ni generen cargos facturados.
En este documento, aprenderás sobre los siguientes temas:
- Cómo escribir interfaces que se puedan probar con el cliente de
Storagede Cloud Storage. - Cómo simular operaciones de lectura
- Cómo simular operaciones de escritura
- Por qué el diseño del cliente de
Storagedifiere de otros clientes de Google Cloud
Dependencias
Agrega la biblioteca cliente de Cloud Storage a tu archivo Cargo.toml:
cargo add google-cloud-storage
Para compilar y ejecutar las pruebas de unidades de este documento, agrega las siguientes dependencias de desarrollo:
cargo add --dev anyhow bytes mockall
cargo add --dev tokio --features macros,rt-multi-thread
Escribe interfaces que se puedan probar
Si no realizas pruebas de unidades en tu código de almacenamiento, puedes escribir interfaces directamente en
términos de Storage, cuyo parámetro de tipo de stub predeterminado es la implementación de producción
del cliente:
Para probar tu código con un cliente simulado, escribe tus interfaces en términos de un
parámetro de tipo genérico T restringido por gcs::stub::Storage + 'static:
Simula operaciones de lectura
Para simular solicitudes de read_object, completa los siguientes pasos:
Escribe una función de aplicación que tome un cliente
&Storage<T>genérico. Por ejemplo, la siguiente función descarga un objeto y cuenta cuántos caracteres de línea nueva contiene:Crea una función auxiliar que construya un flujo de bytes
ReadObjectResponsefalso pasando una carga útil aReadObjectResponse::from_source. Este método acepta los mismos tipos de carga útil queStorage::write_object:Define una estructura simulada que implemente
gcs::stub::Storage. En este documento, se usa la cajamockall, aunque puedes usar un framework de simulación diferente en tus pruebas:Escribe una prueba de unidades que establezca expectativas en la simulación, cree un cliente con
Storage::from_stuby llame acount_newlines:
Simula operaciones de escritura
Para simular solicitudes de write_object, completa los siguientes pasos:
Escribe una función de aplicación que suba un objeto con un cliente
&Storage<T>genérico:Con el struct
MockStoragedefinido en la sección anterior, escribe una prueba de unidades que configure las expectativas en el simulacro, cree un cliente conStorage::from_stuby llame aupload:
Detalles de las expectativas
Debido a que la función upload llama a send_unbuffered, establece la expectativa en
el método expect_write_object_unbuffered correspondiente:
La macro mockall::mock! trata cada creación de instancias genérica como un método
distinto. Especifica el tipo de carga útil concreto, Payload<BytesSource>, en la firma de cierre para que el compilador pueda coincidir con la expectativa del método:
Justificación del diseño
En las siguientes secciones, se explica por qué el cliente Storage usa un parámetro de tipo genérico para su stub en lugar del envío dinámico.
Otros clientes
La mayoría de los clientes, como StorageControl, contienen una implementación compatible con dyn con recuento de referencias (Arc) de su rasgo de stub de forma interna. Usan el envío dinámico para reenviar solicitudes del cliente al stub subyacente, que puede ser la implementación de producción o una simulación.
Debido a que estos clientes usan el envío dinámico, el compilador no necesita resolver el tipo de stub concreto en el tiempo de compilación, y los structs del cliente no necesitan un parámetro de tipo genérico para su stub.
El cliente de Storage
En Rust, un atributo compatible con dyn no puede tener métodos genéricos ni devolver valores impl Future sin empaquetar:
- Los métodos
write_object_bufferedywrite_object_unbufferedson genéricos en el tipo de fuente de carga útil. - Los métodos de atributo
gcs::stub::Storagedevuelvenimpl Futuredirectamente en lugar de empaquetar el futuro devuelto.
El uso del envío dinámico para el cliente Storage requeriría cargas útiles de boxing
y futuros en cada llamada, lo que agregaría asignaciones de montón y sobrecarga de envío dinámico
en la ruta de acceso de los datos. Para evitar esta sobrecarga, el cliente Storage usa un
parámetro de tipo para una implementación concreta del rasgo gcs::stub::Storage.
Código de la aplicación y paquete de pruebas completos
En el siguiente código, se combinan las funciones de la aplicación y las pruebas de unidades en un ejemplo completo:
Ejecuta cargo test para ejecutar test_count_lines y test_upload:
cargo test