Моки
Для моков широко используется библиотека Mockall. Вам нужно переработать код так, чтобы использовать трейты, которые затем можно быстро замокать:
// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
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!(mock_dog.is_hungry(Duration::from_secs(10)));
}
-
Mockall — рекомендуемая библиотека для моков в Android (AOSP). На crates.io есть и другие библиотеки для моков, в частности для HTTP-сервисов. Они работают примерно так же, как Mockall, то есть позволяют легко получить мок-реализацию заданного трейта.
-
Обратите внимание, что моки — довольно спорная тема: они позволяют полностью изолировать тест от его зависимостей. Непосредственный результат — более быстрое и стабильное выполнение тестов. С другой стороны, моки могут быть настроены неправильно и возвращать результат, отличающийся от того, что делали бы реальные зависимости.
Если возможно, рекомендуется использовать реальные зависимости. Например, многие базы данных позволяют настроить бэкенд в памяти. Так вы получаете правильное поведение в тестах, при этом они быстрые и сами за собой убирают.
Аналогично многие веб-фреймворки позволяют запустить внутрипроцессный сервер, который привязывается к случайному порту на
localhost. Всегда предпочитайте это подмене фреймворка моком, поскольку так вы тестируете код в реальной среде. -
Mockall не входит в Rust Playground, поэтому этот пример нужно запускать в локальной среде. Чтобы быстро добавить Mockall в существующий проект Cargo, используйте
cargo add mockall. -
У Mockall обширная функциональность. В частности, можно задавать ожидания, которые зависят от переданных аргументов. Здесь мы используем это, чтобы замокать кота, который проголодается через 3 часа после последнего кормления:
// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
#[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!(mock_cat.is_hungry(Duration::from_secs(5 * 3600)));
assert!(!mock_cat.is_hungry(Duration::from_secs(5)));
}
- Вы можете использовать
.times(n), чтобы ограничить число вызовов метода мока значениемn— если это условие не выполнено, мок автоматически вызовет панику при освобождении.