Не удается проверить аргументы, переданные объекту Jest mocked

#typescript #unit-testing #jestjs #mocking

#typescript #модульное тестирование #jestjs #издевательство

Вопрос:

У меня есть довольно простой класс и метод Typescript. Я хочу протестировать этот метод, используя Jest, чтобы высмеять зависимости этого метода:

 import {DynamoWorkflow} from '..';
import {Injectable} from '@nestjs/common';

@Injectable()
export class PipelineService {
    getCoverageByServiceName(serviceName: string): Promise<QueryResult<PipelineEvent>> {
        return new DynamoWorkflow().queryPipelineEvents(serviceName);
    }
}
  

В моем тесте я хочу подтвердить, что аргумент, переданный методу .queryPipelineEvents() , соответствует моим ожиданиям. Я нахожу это трудным для выполнения.

Вот мой текущий тест:

 //setup mock data...
const mockPipelineEvent: PipelineEvent = new PipelineEvent();
mockPipelineEvent.aut = "fake data";
const mockPipelineEvents: PipelineEvent[] = [mockPipelineEvent];
const mockQueryResult = {results: mockPipelineEvents, total: 1};

//setup mock dependency...
jest.mock('../../../../workflows/dynamoworkflow', () => {
  return {
    DynamoWorkflow: jest.fn().mockImplementation(() => {
      return {
        queryPipelineEvents: () => Promise.resolve(mockQueryResult),
      };
    })
  };
});

describe("PipelineService", () => {
  const mockDynamo = mocked(DynamoWorkflow, true);
    
  beforeEach(() => {
    mockDynamo.mockClear(); 
  })

  it("getCoverageByServiceName returns same data as db supplies", () => {
    const methodArg = "foo-service";
    const serviceUnderTest = new PipelineService();
    const actualResult = serviceUnderTest.getCoverageByServiceName(methodArg);

    // Test #1: confirm the dependency was called
    expect(mockDynamo).toHaveBeenCalledTimes(1); //PASSES

    // Test #2: confirm the dependency method was called with the correct argument
    const mockedDynamoInstance = mockDynamo.mock.instances[0];
    const mockedDynamoMethod = mockedDynamoInstance.queryPipelineEvents;
    expect(mockedDynamoMethod.mock.calls[0][0]).toHaveBeenCalledWith(methodArg);  //ERROR HERE on .mock

    // Test #3: confirm the result is what we expect
    expect(actualResult).resolves.toEqual(mockQueryResult); //PASSES
  });
})
  

Этот код не будет компилироваться. Сообщение Property 'mock' does not exist on type '(serviceName: string) => Promise<QueryResult<PipelineEvent>>'.ts(2339) .

Ошибочный фрагмент кода, который я взял непосредственно из собственной документации Jest.

Я пробовал expect(mockDynamo.queryPipelineEvents).toBeCalledWith(methodArg); , но это тоже не компилируется, ошибка гласит: Property 'queryPipelineEvents' does not exist on type 'MockedObjectDeep<typeof DynamoWorkflow>'.ts(2339)

Я тоже пробовал expect(mockDynamo.mock.instances[0].queryPipelineEvents).toBeCalledWith(methodArg); . Он компилируется и работает нормально, но завершается ошибкой с сообщением:

     expect(received).toBeCalledWith(...expected)

    Matcher error: received value must be a mock or spy function

    Received has value: undefined

      44 |     // expect(mockedDynamoMethod.mock.calls[0][0]).toHaveBeenCalledWith(methodArg);
      45 |     // expect(mockDynamo.queryPipelineEvents).toBeCalledWith(methodArg);
    > 46 |     expect(mockDynamo.mock.instances[0].queryPipelineEvents).toBeCalledWith(methodArg);
         |                                                              ^
      47 | 
      48 |     // Test #3: confirm the result is what we expect
      49 |     expect(actualResult).resolves.toEqual(mockQueryResult);

  

Может кто-нибудь помочь мне понять, как я могу подтвердить, что аргументы издевательского метода были такими, как ожидалось?

Ответ №1:

Сотрудник работал над разными тестами и наткнулся на ответ на этот вопрос. Ключом было назначение метода mock для объекта и метода, над которым издевались. Удалите все издевательства из исходного кода и замените его этим:

 jest.mock('../../../../workflows/dynamoworkflow');
const mockMethod = jest.fn();
mockMethod.mockReturnValue(Promise.resolve(mockQueryResult));
DynamoWorkflow.prototype.queryPipelineEvents = mockMethod; //<- key here!
  

Вот полный рабочий тест:

 describe("PipelineService", () => {

  it("getCoverageByServiceName returns same data as db supplies", () => {
    //setup mock data...
    const mockPipelineEvent: PipelineEvent = new PipelineEvent();
    mockPipelineEvent.aut = "fake data";
    const mockPipelineEvents: PipelineEvent[] = [mockPipelineEvent];
    const mockQueryResult = {results: mockPipelineEvents, total: 1};

    //setup mock...
    jest.mock('../../../../workflows/dynamoworkflow');
    const mockMethod = jest.fn();
    mockMethod.mockReturnValue(Promise.resolve(mockQueryResult));
    DynamoWorkflow.prototype.queryPipelineEvents = mockMethod;

    //exercise the method we're testing...
    const methodArg = "foo-service";
    const serviceUnderTest = new PipelineService();
    const actualResult = serviceUnderTest.getCoverageByServiceName(methodArg);

    // and test...
    expect(mockMethod).toHaveBeenCalledWith(methodArg);
    expect(actualResult).resolves.toEqual(mockQueryResult);
  });

})