如何让 mocha 在断言错误时在 diff 中显示整个对象?

How to have mocha show entire object in diff on assertion error?

我有一个用 mocha 和 chai's expect 创建的单元测试测试用例,我将值对象数组与 JSON 文件的解析内容进行深入比较。

我的记录对象大概有20个属性,目前只有价格会导致不匹配。在diff上,我只看到了其中的五个。

 expect(records).to.deep.equal(expected);

       "data": {
  -      "price": 3578
  +      "price": 3438
         "not_important": "foo"
         "also_not_important": "bar"
       }
       "data": {
  -      "price": 1828
  +      "price": 1698
         "not_important": "foo"
         "also_not_important": "bar"
       }

这在大多数情况下是有用的默认值,但在这种情况下,它混​​淆了哪个特定数据对象正在破坏断言,因为我在这里只看到冗余数据。

假设数据对象中有一个 important 属性 可以很清楚地表明什么期望破坏了测试。因此,我希望能够配置显示哪些属性或在 diff 中显示整个对象。

如何配置 mocha 的差异显示?


这是一个展示问题的人为设计的元句法示例:

import {expect} from "chai";

describe(("diff problem"), () => {
    it("should show case that the diff is not shown properly", () => {
        const actual = {
            a: 1,
            troiz: 0,
            bar: 0,
            baz: 2,
            poit: 3,
            narf: 4,
            fizzbuzz: 117,
            fizz: 5,
            buzz: 4,
            waldo: 115,
            mos: 85465,
            important: "THIS IS IMPORTANT",
        };

        const expected = {
            ...actual,
            a: 0,
        };

        return expect(actual).to.deep.equal(expected);
    });
});

该测试用例的输出将是:

2) SourceParser diff 问题应该在出现一个 属性:

错误时显示整个 diff
  AssertionError: expected { Object (a, troiz, ...) } to deeply equal { Object (a, troiz, ...) }
  + expected - actual

   {
  -  "a": 1
  +  "a": 0
     "bar": 0
     "baz": 2
     "buzz": 4
     "fizz": 5

然而,如果看到:important: "THIS IS IMPORTANT" 也会有所帮助。


这里是数组大小写的修改示例:

describe(("diff problem with an array"), () => {
    it("should show case that the diff is not shown properly for deep equal of arrays", () => {
        const anEntity = {
            a: 1,
            troiz: 0,
            bar: 0,
            baz: 2,
            poit: 3,
            narf: 4,
            fizzbuzz: 117,
            fizz: 5,
            buzz: 4,
            waldo: 115,
            mos: 85465,
            important: "IMPORTANT", // assume that each item has a unique important property, which is why it's helpful for it to be shown
        };

        const offendingItem = {
            ...anEntity,
            a: 0,
        };

        const actual = [
            anEntity,
            offendingItem,
            anEntity,
        ];

        const expected = [
            anEntity,
            anEntity,
            anEntity,
        ];

        return expect(actual).to.deep.equal(expected);
    });

输出将是:

  AssertionError: expected [ Array(3) ] to deeply equal [ Array(3) ]
  + expected - actual

       "troiz": 0
       "waldo": 115
     }
     {
  -    "a": 0
  +    "a": 1
       "bar": 0
       "baz": 2
       "buzz": 4
       "fizz": 5

Louis 的答案修改 chai 也不会变得更好,因为它只会先转储整个实际数组,然后显示无用的差异:

AssertionError: expected [ { a: 1,
    troiz: 0,
    bar: 0,
    baz: 2,
    poit: 3,
    narf: 4,
    fizzbuzz: 117,
    fizz: 5,
    buzz: 4,
    waldo: 115,
    mos: 85465,
    important: 'IMPORTANT' },
  { a: 0,
    troiz: 0,
    bar: 0,
    baz: 2,
    poit: 3,
    narf: 4,
    fizzbuzz: 117,
    fizz: 5,
    buzz: 4,
    waldo: 115,
    mos: 85465,
    important: 'IMPORTANT' },
  { a: 1,
    troiz: 0,
    bar: 0,
    baz: 2,
    poit: 3,
    narf: 4,
    fizzbuzz: 117,
    fizz: 5,
    buzz: 4,
    waldo: 115,
    mos: 85465,
    important: 'IMPORTANT' } ] to deeply equal [ { a: 1,
    troiz: 0,
    bar: 0,
    baz: 2,
    poit: 3,
    narf: 4,
    fizzbuzz: 117,
    fizz: 5,
    buzz: 4,
    waldo: 115,
    mos: 85465,
    important: 'IMPORTANT' },
  { a: 1,
    troiz: 0,
    bar: 0,
    baz: 2,
    poit: 3,
    narf: 4,
    fizzbuzz: 117,
    fizz: 5,
    buzz: 4,
    waldo: 115,
    mos: 85465,
    important: 'IMPORTANT' },
  { a: 1,
    troiz: 0,
    bar: 0,
    baz: 2,
    poit: 3,
    narf: 4,
    fizzbuzz: 117,
    fizz: 5,
    buzz: 4,
    waldo: 115,
    mos: 85465,
    important: 'IMPORTANT' } ]
      + expected - actual

           "troiz": 0
           "waldo": 115
         }
         {
      -    "a": 0
      +    "a": 1
           "bar": 0
           "baz": 2
           "buzz": 4
           "fizz": 5

据我所知,没有内置方法可以让 Chai 或 Mocha 生成差异,这些差异会添加到差异提供的上下文中,一些不 负责的字段 为测试失败。而且我不知道有任何扩展可以满足您的需求。所以我只知道解决方法。


如果您将 truncateThreshold 配置设置设置为更大的值,或者如果您不想要任何 t运行cation,则设置为 0,差异之前出现的失败消息将显示整个对象。因此,如果我将此添加到您的代码中:

chai.config.truncateThreshold = 0; // 0 means "don't truncate, ever".

(此 documentation page 中涵盖了配置选项。)

然后我得到的错误是:

      AssertionError: expected { a: 1,
  troiz: 0,
  bar: 0,
  baz: 2,
  poit: 3,
  narf: 4,
  fizzbuzz: 117,
  fizz: 5,
  buzz: 4,
  waldo: 115,
  mos: 85465,
  important: 'THIS IS IMPORTANT' } to deeply equal { a: 0,
  troiz: 0,
  bar: 0,
  baz: 2,
  poit: 3,
  narf: 4,
  fizzbuzz: 117,
  fizz: 5,
  buzz: 4,
  waldo: 115,
  mos: 85465,
  important: 'THIS IS IMPORTANT' }
      + expected - actual

       {
      -  "a": 1
      +  "a": 0
         "bar": 0
         "baz": 2
         "buzz": 4
         "fizz": 5

此外,在错误消息中获取自定义信息的一种方法是使用断言设置自定义消息,例如:

expect(actual).to.deep.equal(
            expected,
            `failed equality test on object with important field set to: ${actual.important}`)

自定义消息可以根据需要详细或简洁。

如果只有一个字段对您区分对象很重要,自定义消息可能足以获取跟踪问题所需的信息。


对于对象数组,您可以通过遍历 actualexpected 数组并比较每个成员来执行比较。然后它基本上会像上面描述的那样工作。当然,这有缺点:例如,如果第 1 项和第 10 项不同,您将只得到第 1 项的报告,因为测试将以比较失败而结束。当您修复此问题并再次 运行 测试时,您将获得第 10 项的报告。这在实践中是否是一个主要问题取决于您正在测试的数据类型。


在默认差异算法未执行我想要的操作的情况下,我做过的一件事是导入一个我根据自己的喜好配置的差异库,然后使用该库在我关心的对象之间执行差异关于并将结果组合成最终报告,然后用断言进行检查。

同样,我不知道有哪个图书馆可以具体地满足您的需求。但是,我可以想象遍历 actualexpected 数组以生成每对一个差异报告,然后将它们组合成一个更大的包含识别信息的报告。

由于所有反对票,请注意:我是 OP。我的预期解决方案并未解决我的架构决策的实际问题。有一个比较大对象的解决方案是一种代码味道。我重构了我的代码库,这样我就不再需要这个尝试的解决方案了。


您正在尝试解决错误的问题。您的预期解决方案只是一种解决方法。

你的实际问题是依赖于深入比较大量巨大的对象。

您应该重构代码库以允许通过价格计算服务计算价格。使用简单的断言对该服务进行单元测试非常简单。

您可以将 --inline-diffs 添加到 mocha 命令,它将显示带有行号和内联差异的整个对象:

mocha --inline-diffs YourSpec.js

文档有点误导:https://mochajs.org/#diffs