简体   繁体   English

检查是否在单元测试中调用了函数

[英]Check if functions have been called in unit test

Hi I'm trying to write some unit tests in Jest for a module I write, but kind of stuck currently and need some advice how to continue. 嗨,我正在尝试为自己编写的模块在Jest中编写一些单元测试,但是目前有点卡住,并且需要一些如何继续的建议。

export const submitOrder = async (body, key) => {
  const clientRepo = new ClientRepository(db)
  const companyRepo = new CompanyRepository(db)

  const company = await getCompanyByKey(
    companyRepo,
    key
  );

  const client = await createClient(
    clientRepo,
    body
  );

  await addClientToCompany(
    companyRepo,
    client.id,
    company.id
  );

  .. More things
}

I can easily test each function( getCompanyByKey , createClient & addClientToCompany ) by passing down a mocked repository. 我可以通过传递一个模拟的存储库来轻松测试每个函数( getCompanyByKeycreateClientaddClientToCompany )。

But I would also like to test my "flow" of the submitOrder function, by checking if my repository functions have been called. 但是我还想通过检查是否调用了我的存储库函数来测试我的submitOrder函数的“流程”。 But I would then need the instance of each repository, which I don't instantiate until my submitOrder function. 但是我然后需要每个存储库的实例,直到我的submitOrder函数才实例化该实例。

Something like this, which is similar how I unit test my functions. 这样的事情,类似于我对单元功能进行单元测试的方式。

jest.mock('../repositories/ClientRepository');
jest.mock('../repositories/CompanyRepository');

test('should be able to submit an order', async () => {
  const apiKey = 'mocked-super-key';
  const body = getMockData();

  const result = await submitOrder(body, apiKey);
  expect(result).toMatchSnapshot();
  expect(CompanyRepository.findByKey).toHaveBeenCalled();
  expect(ClientRepository.create).toHaveBeenCalled();
  expect(CompanyRepository.addClient).toHaveBeenCalled();
});

Do you have any tips of how I can test if my repositories have been called? 您是否有关于如何测试存储库是否已被调用的提示?

The problem you describe is one of the motivating factors behind dependency injection. 您描述的问题是依赖项注入背后的激励因素之一。

As a single example: your submitOrder() code uses new to directly instantiate a client repository of the specific implementation ClientRepository . 作为一个示例:您的submitOrder()代码使用new直接实例化特定实现ClientRepository的客户端存储库。 Instead, it could declare that it has a dependency - it needs an object that implements the interface of a client repository. 相反,它可以声明它具有依赖项-它需要一个实现客户端存储库接口的对象。 It could then allow for such an object to be supplied by the surrounding environment (a "dependency injection container" in buzzword-ese). 然后,它可以允许周围环境(用流行语“依赖注入容器”提供)提供这种对象。 Then during testing you would create and provide ("inject") a mock implementation instead of the real implementation. 然后,在测试期间,您将创建并提供(“注入”)模拟实现,而不是实际实现。

This has the added benefit that if you ever have to be able to select between multiple "real" implementations, you're already set up to do that too. 这样做还有一个好处,那就是,如果您必须能够在多个“真实”实现之间进行选择,那么您也已经准备好这样做。

There are many ways to achieve this. 有很多方法可以实现这一目标。 It can be as simple as a design pattern, or for a more complete solution you could use a dependency injection framework. 它可以像设计模式一样简单,或者对于更完整的解决方案,您可以使用依赖项注入框架。

If you absolutely cannot refactor your code for this practice, then JavaScript is dynamic enough that you can probably cobble together a way to intercept the invocation of new and thereby simulate dependency injection. 如果您绝对不能为这种实践重构代码,那么JavaScript具有足够的动态性,您可以拼凑一种截取new调用并由此模拟依赖项注入的方法。

You can pass a mock implementation factory as a second parameter to jest.mock , as described in the docs . 您可以将模拟实现工厂作为第二个参数传递给jest.mock如docs中所述

You can use this to mock out the methods that you want to check to have been called. 您可以使用它来模拟要检查的方法。

Try this: 尝试这个:

jest.mock('../repositories/CompanyRepository', () => {
    findByKey: jest.fn(),
    addClient: jest.jn()
});

const mockCreate = jest.fn();

jest.mock('../repositories/CompanyRepository', () => class {
    create(...args) {
        mockCreate(...args);
    }
});

test('should be able to submit an order', async () => {
    const apiKey = 'mocked-super-key';
    const body = getMockData();

    const result = await submitOrder(body, apiKey);
    expect(result).toMatchSnapshot();
    expect(CompanyRepository.findByKey).toHaveBeenCalled();
    expect(ClientRepository.create).toHaveBeenCalled();
    expect(CompanyRepository.addClient).toHaveBeenCalled();
});

Since CompanyRepository is created with “new”, we use a class definition in this case and pass in a mock function that is called when the “create” method is invoked. 由于CompanyRepository是使用“ new”创建的,因此在这种情况下,我们使用类定义并传递一个模拟函数,该函数在调用“ create”方法时被调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM