如何模拟被测试服务调用的函数的实现?

时间:2019-10-24 18:22:08

标签: javascript typescript jestjs nestjs

我正在处理一个NestJS项目,我需要编写服务的单元测试。

我有一个名为BigQueryService的服务,该服务使用@ google-cloud / bigquery来访问Big Query数据集并执行查询。我还有另一个服务(我们称之为MyService),其服务是根据其他逻辑构建我需要的查询,并将其传递给BigQueryService,从中接收查询结果,然后将其返回给控制器,这将在通过端点发送数据。

我需要为MyService编写单元测试,为此,我需要以不需要解析BigQueryService依赖项的方式来模拟BigQueryService。这是我的一些代码:

bigquery.service.ts:

import { Injectable } from '@nestjs/common';
import { BigQuery } from '@google-cloud/bigquery';
...
@Injectable()
export class BigqueryService {
  ...
  constructor(
    ...
  ) {
    ...
  }

  async executeQuery(querySentence: string): Promise<Array<any>> {
    ...
    return response;
  }
}

MyService.service.ts:

import { Injectable } from '@nestjs/common';
import { BigqueryService } from '../bigquery/bigquery.service';
//the following is just a service that helps log the results of this service
import { MyLogger } from '../../config-service/logger.service';
...
@Injectable()
export class MyService {
  constructor(
    private readonly bigqueryService: BigqueryService,
    private readonly logger: MyLogger,
  ) { }
  ...
  async myFunc(request: RequestInterface): Promise<Array<ResponseInterface>> {
    let query = (some code to create a query i want)
    return await this.bigqueryService.executeQuery(query);
  }

对于测试,我遵循了该线程中的答案:Mock a method of a service called by the tested one when using Jest

jest.mock('../services/bigquery/bigquery.service', () => jest.fn()) 
const bq = require('../services/bigquery/bigquery.service')
jest.mock('../config-service/logger.service', () => jest.fn())
const ml = require('../config-service/logger.service')

const executeQuery = jest.fn()
executeQuery.mockReturnValue('desired value')
bq.mockImplementation(() => ({executeQuery}))


describe("Testing consumption moment service function", () => {

  it("should call the mock service", () => {
    const ms = new MyService(bq,ml)
    ms.myFunc(requestBody) //requestBody is a RequestInterface
    expect(bq.executeQuery).toHaveBeenCalled
    expect(bq.executeQuery).toHaveReturned
 });
});

该测试通过了,所以我假设我正确地模拟了bigquery服务。但是,当我试图断言返回的值是正确的值时,我使测试异步,以便直到myFunc实际完成运行并且可以得到比较的结果后,测试才能完成。

 it("should call the mock service", async () => {
   const ms = new MyService(bq,ml) 
   await ms.myFunc(requestBody)
   expect(bq.executeQuery).toHaveBeenCalled
   expect(bq.executeQuery).toHaveReturned
 });

此错误: TypeError:this.bigqueryService.executeQuery不是函数 错误指向myFunc调用this.bigqueryService.executeQuery的行。

我尝试了各种不同的模拟示例,以便可以模拟对此函数的调用,但是没有一个像上面的示例那样接近。我也尝试使用

jest.spyOn(bq, 'executeQuery') 

但是这也表示executeQuery不是函数:由于不是函数,因此无法监视executeQuery属性。改用undefined

有人可以在这里指出正确的方向吗?使该测试有效吗?我在此先感谢大家为您提供的任何帮助。

2 个答案:

答案 0 :(得分:1)

我最终弄清楚了,所以如果有人处在相同的情况下,我在这里找到答案:https://jestjs.io/docs/en/jest-object

测试是这样固定的:

jest.mock('../config-service/logger.service', () => jest.fn())
const ml = require('../config-service/logger.service')
const executeQuery = jest.fn()

describe("Testing service function", () => {

  it("should call the mock service", async () => {
    jest.mock('../services/bigquery/bigquery.service', () => {
      return {
        executeQuery: jest.fn(() => 'desired output'),
      };
    })
    const bq = require('../services/bigquery/bigquery.service')

    const ms = new MyService(bq,ml)
    const p = await ms.myFunc(requestBody) //requestBody is a RequestInterface
    expect(bq.executeQuery).toHaveBeenCalled
    expect(bq.executeQuery).toHaveReturned
    expect(p).toEqual(desired result)
 });
});

答案 1 :(得分:0)

bq.mockImplementation(() => ({executeQuery}))

不是异步的,请尝试返回诺言

bq.mockImplementation(() => (Promise.resolve({executeQuery})))