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

如何在mod tests中导入带#[op]属性的Rust函数?

问题

我在测试一个用#[op](deno_ops的proc macro)标记的异步函数时遇到了报错。

原函数代码:

#[op]
#[instrument(name = "op_xyz", skip_all, ret)]
async fn xyz() -> Result<U256, deno_core::error::AnyError> {...}

把测试写在tests子模块里时,代码如下:

#[cfg(test)]
mod tests {
    use super::op_xyz;

    #[tokio::test]
    async fn test_op_get_latest_nonce() {
      let res = op_xyz().await;
      ...
    }
}

得到错误:

expected function, found `op_xyz`

VS Code的Rust插件提示:

Auto-generated by deno_ops, i.e: #[op]
Use op_get_latest_nonce::decl() to get an op-declaration you can include in a deno_core::Extension

注:把测试函数放在tests模块外面就能正常运行,写法如下:

#[op]
#[instrument(name = "op_xyz", skip_all, ret)]
async fn xyz() -> Result<U256, deno_core::error::AnyError> {...}

#[tokio::test]
async fn test_op_xyz() {
  let res = op_xyz().await;
  ...
}

执行cargo test test_op_xyz -- --nocapture能得到正确结果。

原因

#[op]宏会做两件事:

  1. 在当前模块生成一个和原函数xyz逻辑一致的op_xyz包装函数,这也是外部测试能直接调用op_xyz()的原因;
  2. 同时生成一个同名的op_xyz模块,用来给deno_core注册扩展(就是插件提示里说的带decl()方法的模块)。

当你在子模块里用use super::op_xyz时,Rust会优先把它解析成那个模块,而不是包装函数,所以才会报“期望函数,却找到op_xyz(模块)”的错误。

解决方法

有两种简单的解决方式:

方法一:直接测试原函数xyz

既然op_xyz只是原函数的包装,直接测xyz反而更聚焦业务逻辑:

#[cfg(test)]
mod tests {
    use super::xyz; // 改成导入原函数

    #[tokio::test]
    async fn test_op_get_latest_nonce() {
      let res = xyz().await;
      ...
    }
}

方法二:明确调用包装函数

如果非要测宏生成的包装层,可以用完整路径调用,或者给函数起别名避免混淆:

#[cfg(test)]
mod tests {
    // 方式1:用别名区分模块和函数
    use super::op_xyz as op_xyz_fn;

    #[tokio::test]
    async fn test_op_get_latest_nonce() {
      // 用别名调用函数
      let res = op_xyz_fn().await;
      // 或者直接写完整路径:super::op_xyz().await;
      ...
    }
}

额外说明

如果需要测试op在deno运行时的完整行为(比如从JS调用op),就得用插件提示的op_xyz::decl()来注册扩展,再通过deno_core的Runtime来测试:

#[cfg(test)]
mod tests {
    use deno_core::{Extension, Runtime};

    #[tokio::test]
    async fn test_op_in_runtime() {
        let ext = Extension::builder()
            .ops(vec![super::op_xyz::decl()])
            .build();
        
        let mut runtime = Runtime::new(ext).unwrap();
        // 执行JS代码调用op
        let result = runtime.execute_script("test.js", r#"
            const result = await Deno.core.opAsync("xyz");
            console.log(result);
        "#).await;
        
        assert!(result.is_ok());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 07:45:31