您如何模拟 Apollo Server RESTDataSource 以使用 Jest 进行单元测试?

Cer*_*ean 8 unit-testing typescript apollo jestjs apollo-server

我正在尝试测试基于 Apollo Server 的 Apollo Server 中的数据源RESTDataSourcehttps://www.apollographql.com/docs/apollo-server/data/data-sources/#rest-data-source)。我正在尝试使用 Jest 对其进行测试。该类具有从外部 REST API 以及从调用第二个 API 的另一个模块中提取数据的方法(因此这RESTDataSource最终取决于两个外部 API,其中一个在此处直接调用,一个在此处间接调用) )。

我不是测试专家,我不清楚如何模拟外部 API。GraphQL Tools 有一些工具可以让你模拟你的服务器,但我不确定那是我想要的。或者我应该使用Jest 的方法来模拟ES6 类,忘记这是一个 GraphQL 服务器?如果是这样,由于我正在使用 a class,我是否只是使用类似于模拟方法的方法来模拟MyClass.myMethod方法?

如果我使用的是 TypeScript(我就是),除了设置 Jest 以使用 TypeScript 之外,我的操作方式有什么变化吗?

显然正确的路线是选择上面的选项之一,但我有点“只见树木不见森林”,也就是说,由于我缺乏测试经验,我不知道哪个是正确的要遵循的路线。

感谢您提供任何线索。

Lau*_*rpf 5

单元测试

您可以按照 Apollo Spectrum 聊天中的 apollo-datasource-rest + Typescript + Jest中的建议,通过模拟RESTDataSourcein来对数据源进行单元测试。apollo-datasource-rest

对于该数据源:

import { RESTDataSource } from 'apollo-datasource-rest'

export class MyRestDataSource extends RESTDataSource {
  async getStackoverflow(): Promise<string> {
    return this.get('https://stackoverflow.com/')
  }
}

Run Code Online (Sandbox Code Playgroud)

您可以编写这样的单元测试:

import { MyRestDataSource } from './MyRestDataSource'

const mockGet = jest.fn()
jest.mock('apollo-datasource-rest', () => {
  class MockRESTDataSource {
    baseUrl = ''
    get = mockGet
  }
  return {
    RESTDataSource: MockRESTDataSource,
  }
})

describe('MyRestDataSource', () => {
  it('getStackoverflow gets data from correct URL', async () => {
    const datasource = new MyRestDataSource()

    await datasource.getStackoverflow()

    expect(mockGet).toBeCalledWith('https://stackoverflow.com/')
  })
})
Run Code Online (Sandbox Code Playgroud)

集成测试

在大多数情况下,我更喜欢使用apollo-server-testing 进行集成测试,而不是对数据源进行单元测试:您针对服务器运行 GraphQL 并测试从解析器到数据源的整个路径。如果这样做,请考虑使用例如nock来模拟数据源发出的 HTTP 请求。

打字稿

无论您使用的是 TypeScript 还是 JavaScript,一般方法都应该是相同的,只有一些细微的差别。例如,使用 JavaScript,您的单元测试可以直接替换get数据源中的:

const MyRestDataSource = require('./MyRestDataSource')

describe('MyRestDataSource', () => {
  it('getStackoverflow gets data from correct URL', async () => {
    const datasource = new MyRestDataSource()
    datasource.get = jest.fn()
    await datasource.getStackoverflow()

    expect(datasource.get).toBeCalledWith('https://stackoverflow.com/')
  })
})
Run Code Online (Sandbox Code Playgroud)

但使用 TypeScript 会导致编译器错误,因为它get是受保护的:

MyRestDataSource.test.ts:6:16 - 错误 TS2445:属性“get”受保护,只能在类“RESTDataSource”及其子类中访问。