【问题标题】:Jest expect an object with functions inside开玩笑期望一个内部有函数的对象
【发布时间】:2020-04-17 09:52:07
【问题描述】:

我正在编写一个 Jest 测试,其中我调用一个函数并期望返回一个对象,如下所示:

const repository = container => {

  const makeBooking = (user, booking) => {
    'make booking function called'
  }

  const generateTicket = (paid, booking) => {
    console.log('generate ticket function called')
  }

  const getOrderById = orderId => {
    console.log('get order by ID called')
  }

  const disconnect = () => {
    console.log('disconnect method called')
  }

  return {
    makeBooking,
    getOrderById,
    generateTicket,
    disconnect
  }
}

为了举例,所有这些函数现在都是示例。我现在,导出函数,然后在测试中使用它,如下所示:

container = {}

describe('Repository', () => {
  it('should connect with a container', () => {
    let hello = repository(container)

    expect(hello).toMatchObject({
      makeBooking: jest.fn('makeBooking'),
      getOrderById: jest.fn('getOrderById'),
      generateTicket: jest.fn('generateTicket'),
      disconnect: jest.fn('disconnect')
    })
  })
})


我得到的错误是:

 Expected value to match object:
      {"disconnect": [Function mockConstructor], "generateTicket": [Function mockConstructor], "getOrderById": [Function mockConstructor], "makeBooking": [Function mockConstructor]}
    Received:
      {"disconnect": [Function disconnect], "generateTicket": [Function generateTicket], "getOrderById": [Function getOrderById], "makeBooking": [Function makeBooking]}

我需要模拟从存储库对象返回的对象。但是,该对象由代码中所示的命名函数组成。 有没有办法模拟里面有函数的对象?

【问题讨论】:

  • 我不清楚您要模拟什么 - 如果您正在测试 repository.connect,您不应该模拟其中的内容。如果你只关心你可以做的形状,例如expect(hello).toMatchObject({ makeBooking: expect.anything(), ... });,但在某些时候你也应该测试这些功能。
  • 我上面粘贴的代码有一个小错误。我不是在模拟连接,我是在模拟存储库对象的返回对象。
  • Expect.anything() 正在工作,但无论如何我可以确定它们确实是函数吗?
  • 不过,您没有显示任何模拟设置;目前尚不清楚您为什么认为此测试可能会通过。我认为您可以使用expect.any(Function),但这似乎不是一种可靠的测试方法。
  • 本单元的范围,原子测试只是测试存储库,它实际上是一个适配器,一旦被调用,是否会提供必要的存储库对象。这些存储库功能的实现将在其他地方进行测试;不在这里。我希望你明白。感谢您的帮助。

标签: javascript node.js unit-testing jestjs jest-fetch-mock


【解决方案1】:

您可以使用jest.spyOnrepository 的方法制作存根。

您模拟或存根存储库的方法,您需要使用它们。这就是为什么 service.js 来自哪里,当然,您可以在任何地方使用存储库。所以,实际上要测试的方法是service.makeBooking。然后,您可以对存储库的makeBooking 方法进行断言,例如,检查存储库的模拟/存根makeBooking 方法是否已被调用。

这里我们使用依赖注入模式将模拟的hello对象注入service.makeBooking(hello)方法。

例如

repository.js:

const repository = (container) => {
  const makeBooking = (user, booking) => {
    'make booking function called';
  };

  const generateTicket = (paid, booking) => {
    console.log('generate ticket function called');
  };

  const getOrderById = (orderId) => {
    console.log('get order by ID called');
  };

  const disconnect = () => {
    console.log('disconnect method called');
  };

  return {
    makeBooking,
    getOrderById,
    generateTicket,
    disconnect,
  };
};

module.exports = repository;

repository.test.js:

const repository = require('./repository');

const container = {};

describe('Repository', () => {
  it('should connect with a container', () => {
    let hello = repository(container);

    expect(hello).toMatchObject({
      makeBooking: expect.any(Function),
      getOrderById: expect.any(Function),
      generateTicket: expect.any(Function),
      disconnect: expect.any(Function),
    });
  });

  it('should generate ticket', () => {
    let hello = repository(container);
    const logSpy = jest.spyOn(console, 'log');
    hello.generateTicket();
    expect(logSpy).toBeCalledWith('generate ticket function called');
  });

  // rest test cases same as above
});

带有覆盖率报告的单元测试结果:

 PASS  stackoverflow/61268658/repository.test.js (11.281s)
  Repository
    ✓ should connect with a container (5ms)
    ✓ should generate ticket (19ms)

  console.log node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866
    generate ticket function called

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |      80 |      100 |      40 |      80 |                   
 repository.js |      80 |      100 |      40 |      80 | 11,15             
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        13.132s

service.js:

const service = {
  makeBooking(hello) {
    return hello.makeBooking();
  },
};

module.exports = service;

service.test.js:

const service = require('./service');
const repository = require('./repository');
const container = {};

describe('service', () => {
  it('should init', () => {
    let hello = repository(container);
    jest.spyOn(hello, 'makeBooking').mockReturnValueOnce('fake data');
    const actual = service.makeBooking(hello);
    expect(actual).toEqual('fake data');
    expect(hello.makeBooking).toBeCalledTimes(1);
  });
});

带有覆盖率报告的单元测试结果:

 PASS  stackoverflow/61268658/service.test.js (10.94s)
  service
    ✓ should init (4ms)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   76.92 |      100 |   33.33 |   76.92 |                   
 repository.js |      70 |      100 |      20 |      70 | 7,11,15           
 service.js    |     100 |      100 |     100 |     100 |                   
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        12.278s

【讨论】:

  • 我不理解 service.js 文件。想说明清楚?不过我理解直觉!
  • 您认为这是在测试什么? OP 似乎正在尝试测试 repository,但您发明了 service 并且似乎正在测试 that。在这种情况下,不需要使用真实的存储库,您可以通过例如{ makeBooking: jest.fn() } 作为hello 参数。
  • @jonrsharpe 好的。如果在service.js 模块中使用const repository = require('./repository') 而不是依赖注入模式会怎样? OP 说他想模拟/存根 repository 的方法。
  • 好吧,如果?很难说,因为你发明了服务,我们不知道 OP 是如何实际使用存储库的。他们的测试是describe('Repository',他们正在测试存储库本身。
  • 我需要 expect.any(Function) 所以它对我很有帮助。
【解决方案2】:

这就是我要找的东西:

expect.objectContaining({ 
   theProperty: expect.any(Function) 
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 2018-08-10
    • 2023-02-03
    • 2018-10-23
    • 2019-04-08
    • 2019-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多