You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

依赖不兼容时,如何运行Rust树莓派项目的单元测试?

解决MacOS下Rust项目单元测试因rppal依赖编译失败的问题

因为rppal是专门针对树莓派硬件(GPIO等)的库,MacOS没有对应的硬件支持,直接编译会失败。可以通过分离硬件逻辑+条件编译+Mock实现的方式,让单元测试在MacOS上正常运行,同时保留树莓派目标平台的正常编译。

步骤1:分离核心逻辑与硬件依赖代码

把依赖rppal的硬件操作(比如GPIO控制风扇)和业务逻辑(比如温度判断、风扇启停逻辑)拆分开,用trait定义接口,让业务逻辑依赖抽象而非具体的硬件实现。

示例代码:

// src/fan.rs
// 定义风扇控制的抽象接口
pub trait FanController {
    fn turn_on(&mut self);
    fn turn_off(&mut self);
}

// 树莓派硬件实现,仅在arm-linux目标下编译
#[cfg(target_arch = "arm")]
pub struct RpiFanController {
    gpio: rppal::gpio::Gpio,
    pin: rppal::gpio::Pin,
}

#[cfg(target_arch = "arm")]
impl RpiFanController {
    pub fn new(pin_number: u8) -> Result<Self, Box<dyn std::error::Error>> {
        let gpio = rppal::gpio::Gpio::new()?;
        let pin = gpio.get(pin_number)?.into_output();
        Ok(Self { gpio, pin })
    }
}

#[cfg(target_arch = "arm")]
impl FanController for RpiFanController {
    fn turn_on(&mut self) {
        self.pin.set_high();
    }

    fn turn_off(&mut self) {
        self.pin.set_low();
    }
}

// Mock实现,用于MacOS下的单元测试
#[cfg(not(target_arch = "arm"))]
pub struct MockFanController {
    pub is_on: bool,
}

#[cfg(not(target_arch = "arm"))]
impl MockFanController {
    pub fn new() -> Self {
        Self { is_on: false }
    }
}

#[cfg(not(target_arch = "arm"))]
impl FanController for MockFanController {
    fn turn_on(&mut self) {
        self.is_on = true;
    }

    fn turn_off(&mut self) {
        self.is_on = false;
    }
}

步骤2:配置Cargo.toml的条件依赖

让rppal仅在树莓派目标平台下被引入,避免MacOS编译时尝试构建它:

[package]
name = "fan_control"
version = "0.1.0"
edition = "2021"

[dependencies]
# 仅在arm架构下引入rppal
rppal = { version = "0.13.1", optional = true }

[features]
# 默认不启用rppal,编译树莓派版本时手动开启
default = []
rpi = ["rppal"]

之后可以用cfg(feature = "rpi")替代或结合target_arch = "arm",确保只有编译树莓派版本时才编译硬件相关代码。

步骤3:编写跨平台的单元测试

测试时使用Mock实现,验证业务逻辑的正确性,无需依赖真实硬件:

// src/lib.rs
mod fan;

use fan::FanController;

pub fn control_fan<T: FanController>(controller: &mut T, temp: f32) {
    if temp > 60.0 {
        controller.turn_on();
    } else {
        controller.turn_off();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::fan::MockFanController;

    #[test]
    fn test_fan_turns_on_when_hot() {
        let mut fan = MockFanController::new();
        control_fan(&mut fan, 65.0);
        assert!(fan.is_on);
    }

    #[test]
    fn test_fan_turns_off_when_cool() {
        let mut fan = MockFanController::new();
        fan.turn_on(); // 先设为开启状态
        control_fan(&mut fan, 55.0);
        assert!(!fan.is_on);
    }
}

编译与测试命令

  • 在MacOS上运行单元测试:直接执行cargo test,此时会使用Mock实现,不会编译rppal。
  • 编译树莓派目标版本:执行cargo build --target armv7-unknown-linux-musleabihf --features rpi,此时会引入rppal并编译硬件相关代码。

这样就能在MacOS上正常跑单元测试验证业务逻辑,同时不影响树莓派目标平台的编译运行。

内容的提问来源于stack exchange,提问作者clash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 02:10:20