【问题标题】:Is it possible for the assert_eq macro to show a diff when two strings aren't equal?当两个字符串不相等时,assert_eq 宏是否可以显示差异?
【发布时间】:2020-01-14 20:04:19
【问题描述】:

我正在为语言标记器编写一些测试,并将标记器生成的标记化的 JSON 序列化版本与已知良好标记化的序列化进行比较。所以我有一些这样的测试:

#[test]
fn test_tokenize() {
    let actual_token_json = /* string */;
    let expected_token_json = /* string */;

    assert_eq!(actual_token_json, expected_token_json);
}

但是,当这些测试失败时,cargo test 只是说 JSON 字符串不相等并将它们都打印出来,这没什么用。由于 JSON 字符串都打印得很漂亮,如果cargo test 打印出两个字符串的行差异会更有帮助。有什么办法可以做到吗?

更新: 有人编辑了这篇文章的标题,但删除了一条重要信息:当 两个字符串 不相等时,我正在寻找 line 差异。我在这里看到的答案之一是更一般的问题,即在两个值不相等时获取 line and 字符 的调试表示的差异。这不是我需要的,就是不是我需要的。例如,两个字符串的调试表示的差异不会给我一个行差异,而是一个大的、复杂的字符差异(因为这些行在调试表示中显示为转义的“\n”标记)。

【问题讨论】:

    标签: unit-testing rust macros assert rust-cargo


    【解决方案1】:

    可以,但标准库提供的assert_eq 宏不能。您可以使用 pretty_assertions crate,它旨在满足您的需求。


    实际上,内置宏可以使用两个以上的参数,通过自定义消息扩展它来提供有关断言的更多信息。所以从技术上讲,如果您自己提供某种差异实现或外部实现,即DisplayDebug,则可以将其传递给宏。严格来说,这个宏在某些方面也可以用于这样的事情。

    【讨论】:

    • 哇,这是一个非常好的差异显示;我使用的库(或版本)不太好,我需要切换/升级!
    • 这很有用,但事实证明,它不适用于我原来的问题。我正在寻找两个字符串不相等时的行差异,而不是两个值不相等时的两个调试表示的字符差异。使用pretty_assertions,当两个字符串不同时,我会遇到很大的麻烦,因为换行符显示为“\n”转义序列。
    【解决方案2】:

    请参阅我的帖子中的更新,了解为什么 pretty_assertions 不能完全解决我的特定问题。相反,我最终只使用了pretty_assertions 在内部使用的difference 库。我刚刚为difference::Changeset 做了一个包装结构,这样我就可以覆盖它的fmt::Display 实现:

    fn prefix_lines(prefix: &str, lines: &str) -> String {
        lines
            .lines()
            .map(|i| [prefix, i].concat())
            .collect::<Vec<String>>()
            .join("\n")
    }
    
    pub struct Diff(difference::Changeset);
    
    impl Diff {
        pub fn new(left: &str, right: &str) -> Self {
            Self(difference::Changeset::new(left, right, "\n"))
        }
    }
    
    impl fmt::Display for Diff {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            for d in &self.0.diffs {
                match *d {
                    difference::Difference::Same(ref x) => {
                        write!(f, "{}{}", prefix_lines(" ", x), self.0.split)?;
                    }
                    difference::Difference::Add(ref x) => {
                        write!(f, "\x1b[92m{}\x1b[0m{}", prefix_lines("+", x), self.0.split)?;
                    }
                    difference::Difference::Rem(ref x) => {
                        write!(f, "\x1b[91m{}\x1b[0m{}", prefix_lines("-", x), self.0.split)?;
                    }
                }
            }
            Ok(())
        }
    }
    

    然后我只有一个宏,就像在pretty_assertions 实现中一样,它创建该结构的一个实例,并在断言失败时在紧急消息中对其进行字符串格式化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-28
      • 2021-01-05
      • 2018-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多