Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Моки

Для моков широко используется библиотека 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)));
}
This slide should take about 5 minutes.
  • 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 — если это условие не выполнено, мок автоматически вызовет панику при освобождении.