Saltar al contenido principal

Simulación

Los mocks se usan en pruebas para excluir funcionalidades que no se quieren probar. Los mocks se usan cuando es difícil probar contra un componente externo.

consejo

El Soroban Rust SDK facilita probar contra un contrato real tanto como probar contra un mock de un contrato. En algunos ecosistemas se evitan las pruebas de integración. No ocurre así en el ecosistema Stellar. Consulta Pruebas de Integración.

Cómo escribir pruebas con mocks

El siguiente es un ejemplo de una prueba que usa un mock, escrita para probar el contrato increment-with-pause. El contrato tiene una función increment que aumenta un contador en uno cada vez que se invoca. El contrato depende de otro contrato que controla si la función de incremento está en pausa.

Las siguientes pruebas configuran el contrato increment-with-pause junto con un mock del contrato de pausa, e invocan varias veces la función del contrato de incremento bajo diferentes condiciones esperadas del contrato de pausa.

La siguiente prueba verifica que cuando el contrato de pausa no está en pausa, el contrato de incremento funciona.

#![cfg(test)]
use crate::{Error, IncrementContract, IncrementContractArgs, IncrementContractClient, Pause};
use soroban_sdk::{contract, contractimpl, Env};

mod notpaused {
use super::*;
#[contract]
pub struct Mock;
#[contractimpl]
impl Pause for Mock {
fn paused(_env: Env) -> bool {
false
}
}
}

#[test]
fn test_notpaused() {
let env = Env::default();
let pause_id = env.register(notpaused::Mock, ());
let contract_id = env.register(
IncrementContract,
IncrementContractArgs::__constructor(&pause_id),
);
let client = IncrementContractClient::new(&env, &contract_id);

assert_eq!(client.increment(), 1);
assert_eq!(client.increment(), 2);
assert_eq!(client.increment(), 3);
}

La siguiente prueba verifica que cuando el contrato de pausa está en pausa, la función del contrato de incremento rechaza los intentos de incrementar.

#![cfg(test)]
use crate::{Error, IncrementContract, IncrementContractArgs, IncrementContractClient, Pause};
use soroban_sdk::{contract, contractimpl, Env};

mod paused {
use super::*;
#[contract]
pub struct Mock;
#[contractimpl]
impl Pause for Mock {
fn paused(_env: Env) -> bool {
true
}
}
}

#[test]
fn test_paused() {
let env = Env::default();
let pause_id = env.register(paused::Mock, ());
let contract_id = env.register(
IncrementContract,
IncrementContractArgs::__constructor(&pause_id),
);
let client = IncrementContractClient::new(&env, &contract_id);

assert_eq!(client.try_increment(), Err(Ok(Error::Paused)));
}

La mayoría de las pruebas, ya sean unitarias, con mocks o de integración, serán muy similares a estas. Harán cuatro cosas:

  1. Crear un ambiente, el Env.
  2. Registrar el/los contratos que se van a probar.
  3. Invocar funciones usando el cliente generado.
  4. Verificar el resultado.
advertencia

La simulación introduce supuestos sobre el comportamiento de otro contrato. Aunque el contrato publique una interfaz que diga que devolverá un bool (true/false), los contratos pueden devolver cualquier tipo.

impl Pause {
fn paused(env: Env) -> ? { ? }
}

Esta es una razón por la que es útil probar y hacer fuzzing usando dependencias reales y programar con defensiva asumiendo que cualquier llamada externa puede causar que tu contrato falle.

Consulta Pruebas de Integración para saber cómo probar con dependencias reales.

El Soroban Rust SDK maneja las llamadas a contratos de forma defensiva para que cualquier error inesperado o tipo inesperado devuelto haga que la ejecución se detenga. El SDK también ofrece métodos para realizar estas llamadas y para interceptar situaciones de error. Consulta Realizar llamadas entre contratos para más detalles.