Mocking
Para mocking, Mockall é uma biblioteca muito usada. Você precisa refatorar seu código para usar traits, que você pode então rapidamente “mockar”:
use std::time::Duration;
#[mockall::automock]
pub trait Pet {
fn is_hungry(&self, since_last_meal: Duration) -> bool;
}
#[test]
fn test_robot_dog() {
let mut mock_dog = MockPet::new();
mock_dog.expect_is_hungry().return_const(true);
assert_eq!(mock_dog.is_hungry(Duration::from_secs(10)), true);
}
-
Mockall é a biblioteca de mocking recomendada para Android (AOSP). Existem outras bibliotecas de mocking disponíveis em crates.io, em particular na área de mocking de serviços HTTP. As outras bibliotecas de mocking funcionam de maneira semelhante ao Mockall, o que significa que elas facilitam a obtenção de uma implementação de mock de um determinado trait.
-
Observe que o mocking é um tanto controverso: mocks permitem que você isole completamente um teste de suas dependências. O resultado imediato é uma execução de teste mais rápida e estável. Por outro lado, os mocks podem ser configurados incorretamente e retornar uma saída diferente daquela que as dependências reais fariam.
Se possível, é recomendável que você use as dependências reais. Como exemplo, muitos bancos de dados permitem que você configure um backend em memória. Isso significa que você obtém o comportamento correto em seus testes, além de serem rápidos e limparem automaticamente após si mesmos.
Da mesma forma, muitos frameworks da web permitem que você inicie um servidor em processo que se vincula a uma porta aleatória em
localhost
. Sempre prefira isso a mockar o framework pois isso ajuda você a testar seu código no ambiente real. -
Mockall não faz parte do playground do Rust, então você precisa executar este exemplo em um ambiente local. Use
cargo add mockall
para adicionar rapidamente o Mockall a um projeto Cargo existente. -
Mockall tem muito mais funcionalidades. Em particular, você pode configurar expectativas que dependem dos argumentos passados. Aqui usamos isso para “mockar” um gato que fica com fome 3 horas após a última vez que foi
#[test]
fn test_robot_cat() {
let mut mock_cat = MockPet::new();
mock_cat
.expect_is_hungry()
.with(mockall::predicate::gt(Duration::from_secs(3 * 3600)))
.return_const(true);
mock_cat.expect_is_hungry().return_const(false);
assert_eq!(mock_cat.is_hungry(Duration::from_secs(1 * 3600)), false);
assert_eq!(mock_cat.is_hungry(Duration::from_secs(5 * 3600)), true);
}
- Você pode usar
.times(n)
para limitar o número de vezes que um método mock pode ser chamado paran
— o mock automaticamente irá gerar um pânico quando descartado se isso não for satisfeito.