【问题标题】:Jest, data in one test bleeding to another开玩笑,一个测试中的数据流向另一个
【发布时间】:2021-06-16 00:51:45
【问题描述】:

我一直在开玩笑地遇到这个问题,我在一个测试中设置的数据正在蔓延到另一个测试中并导致它失败。

让我尝试显示一些代码

spec.ts

const MOCK_PRODUCT = require('../dummydata/dummydata.json');

describe('function 1', () => {
  test('something', () => {
    const productData = MOCK_PRODUCT;
    expect(...) // works fine
  });

  test('something else', () => {
    const productData = MOCK_PRODUCT;
    productData.someField.push({...})
    expect(...) // works fine
  });
});

describe('function 2', () => {
  test('something more', () => {
    const productData = MOCK_PRODUCT;
    expect(...) // fails
  });
});

我的测试文件是这样的。每个函数都有一个 describe 块,describe 块中有多个测试。

我观察到的是,当我在第二个测试中更改 productData 时,如您所见,更改后的数据在下一个描述块中的所有测试中都可用,导致它们失败。

我做错了吗?有什么遗漏吗?

【问题讨论】:

    标签: jestjs


    【解决方案1】:

    不幸的是,这是设计使然。该脚本只是从上到下运行。 beforeAllbeforeEachafterEachafterAll 函数可以帮助您从测试方法中提取一些代码。

    您还可以使用lodash 中的cloneDeep 函数在每次测试运行之前制作测试数据的完全独立副本。

    const MOCK_PRODUCT = require('../dummydata/dummydata.json');
    const _ = require('lodash'),
    let productData = undefined;
    beforeEach(() => {
      productData = _.cloneDeep(MOCK_PRODUCT);
    })
    
    describe('function 1', () => {
      test('something', () => {
        expect(...) // works fine
      });
    
      test('something else', () => {
        productData.someField.push({...})
        expect(...) // works fine
      });
    });
    
    describe('function 2', () => {
      test('something more', () => {
        expect(...) // fails
      });
    });
    

    【讨论】:

    • 两者都试过了,它的行为是一样的。由于某种原因,它没有清除先前设置的字段
    • 好的,那么您似乎需要大男孩 lodash deepclone,它会为您创建所需测试数据的全新副本。我会相应地更新答案,我不知道需要缓存加载的对象。
    • @aneeshere 我可以帮你解决这个问题吗?
    • 我试过一次,但没有成功。由于其他承诺,我无法对其进行更多检查。
    【解决方案2】:

    似乎MOCK_PRODUCT 是一个对象,那么当你设置const productData = MOCK_PRODUCT; 时,productDataMOCK_PRODUCT 的引用。这意味着如果您更新 producData 内容,MOCK_PRODUCT 内容也会被更新。

    在上一个测试中,您更新了productData 对象,那么下一个测试将无法按您的预期工作。

    避免它的简单方法是停止使用引用方式,只需为每个测试克隆到一个新对象。

    const productData = {...MOCK_PRODUCT};
    

    我的建议,在顶层定义productData 变量,在beforeEach 中为其分配克隆的MOCK_PRODUCT。然后在每个测试中使用productData

    【讨论】:

    • 你的意思是,这是一个对象引用被更新的经典案例吗?每个测试实际上都是从这个参考中挑选出来的?
    • @aneeshere 是的,MOCK_PRODUCT 定义为全局变量,我猜它是一个对象。
    • 是的,它是一个对象。我以前做过某种克隆,但让我再做一次。我可以在 beforeEach 中进行克隆,对吗?还是我应该在每次测试中都这样做?还是两者本质上是一样的?
    • 是的,您可以在 breforeEach 块中进行操作。
    • productData.someField.push({...}) 建议 someField 是一个数组。扩展运算符执行浅拷贝,因此如果您向副本添加新属性或更改它们的标量值,原始将保持不变。但是如果你不使用深度克隆,你会推送到原始的 someField 数组。
    猜你喜欢
    • 2019-11-10
    • 2020-05-26
    • 1970-01-01
    • 2022-10-06
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 2018-08-06
    • 2018-11-24
    相关资源
    最近更新 更多