programing

타이프 스크립트 및 재스트:시뮬레이션된 함수의 유형 오류 방지

newstyles 2023. 3. 10. 21:19

타이프 스크립트 및 재스트:시뮬레이션된 함수의 유형 오류 방지

Jest를 사용하여 외부 모듈을 시뮬레이트할 수 있습니다.jest.mock()method를 사용하여 모듈의 기능을 자동 검출합니다.

그런 다음 원하는 대로 조롱된 모듈의 조롱된 함수를 조작하고 질문할 수 있습니다.

예를 들어, Axios 모듈을 조롱하기 위한 다음 예를 생각해 보겠습니다.

import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';

jest.mock('axios');

it('Calls the GET method as expected', async () => {
  const expectedResult: string = 'result';

  axios.get.mockReturnValueOnce({ data: expectedResult });
  const result = await myModuleThatCallsAxios.makeGetRequest();

  expect(axios.get).toHaveBeenCalled();
  expect(result).toBe(expectedResult);
});

위의 내용은 Jest에서는 정상적으로 실행되지만 Typescript 오류가 발생합니다.

유형 '(url: string, config:)'에 속성 'mockReturnValueOnce'가 없습니다.AxiosRequestConfig | 정의되지 않음) => AxiosPromise' 입니다.

의 typedefaxios.get을 포함하지 않는 것은 당연하다mockReturnValueOnce소유물.Typescript를 강제로 처리하도록 할 수 있습니다.axios.get오브젝트 리터럴로 변환하여Object(axios.get), 그러나:

형식 안전을 유지하면서 기능을 모의하는 관용적인 방법은 무엇입니까?

이 코드 줄 추가const mockedAxios = axios as jest.Mocked<typeof axios>그리고 조롱당한 것들을 이용해서mockReturnValueOnce를 호출하는 Axios.코드를 사용하여 다음과 같이 해야 합니다.

import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

it('Calls the GET method as expected', async () => {
  const expectedResult: string = 'result';

  mockedAxios.get.mockReturnValueOnce({ data: expectedResult });
  const result = await myModuleThatCallsAxios.makeGetRequest();

  expect(mockedAxios.get).toHaveBeenCalled();
  expect(result).toBe(expectedResult);
});

의 기능을 사용해 주세요.ts-jest

mockedtest helper는 소스 입력에 따라 시뮬레이션된 모듈 및 그 상세 메서드에 대한 입력 정보를 제공합니다.최신 TypeScript 기능을 사용하기 때문에 IDE에는 (재밌는 것이 아니라) 인수 타입이 완성되어 있습니다.Mock Instance)

import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';
import { mocked } from 'ts-jest/utils'

jest.mock('axios');

// OPTION - 1
const mockedAxios = mocked(axios, true)
// your original `it` block
it('Calls the GET method as expected', async () => {
  const expectedResult: string = 'result';

  mockedAxios.mockReturnValueOnce({ data: expectedResult });
  const result = await myModuleThatCallsAxios.makeGetRequest();

  expect(mockedAxios.get).toHaveBeenCalled();
  expect(result).toBe(expectedResult);
});

// OPTION - 2
// wrap axios in mocked at the place you use
it('Calls the GET method as expected', async () => {
  const expectedResult: string = 'result';

  mocked(axios).get.mockReturnValueOnce({ data: expectedResult });
  const result = await myModuleThatCallsAxios.makeGetRequest();

  // notice how axios is wrapped in `mocked` call
  expect(mocked(axios).get).toHaveBeenCalled();
  expect(result).toBe(expectedResult);
});

얼마나 훌륭한지 강조할 수 없다.mocked이제 더 이상 활자 캐스팅을 하지 않는 거야

형식 안전을 유지하면서 함수를 관용적으로 조롱하려면 spyOnmockReturnValueOnce와 함께 사용합니다.

import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';

it('Calls the GET method as expected', async () => {
  const expectedResult: string = 'result';

  // set up mock for axios.get
  const mock = jest.spyOn(axios, 'get');
  mock.mockReturnValueOnce({ data: expectedResult });

  const result = await myModuleThatCallsAxios.makeGetRequest();

  expect(mock).toHaveBeenCalled();
  expect(result).toBe(expectedResult);

  // restore axios.get
  mock.mockRestore();
});

기존 모듈을 확장하기 위해 Import에 새로운 기능을 제공하는 일반적인 접근법declare module "axios" { ... }모듈 전체를 대상으로 해야 하기 때문에 이 방법은 권장하지 않습니다.한 테스트에서는 모크를 사용할 수 있지만 다른 테스트에서는 사용할 수 없는 경우가 있습니다.

이 경우 타입 세이프 접근방식은 필요한 경우 타입을 주장하는 것이다.

  (axios.get as jest.Mock).mockReturnValueOnce({ data: expectedResult });
  ...
  expect(axios.get as jest.Mock).toHaveBeenCalled();

@hutabalian 사용 시 코드가 잘 작동합니다.axios.get또는axios.post단, 를 사용하는 경우config요청의 경우 다음 코드를 사용합니다.

const expectedResult: string = 'result';
const mockedAxios = axios as jest.Mocked<typeof axios>;
mockedAxios.mockReturnValueOnce({ data: expectedResult });

다음과 같은 오류가 발생합니다.

TS2339(TS) 유형 'MockReturnValueOnce' 속성이 'Mocked'에 없습니다.

대신 다음과 같이 해결할 수 있습니다.

AxiosRequest.test.tsx

import axios from 'axios';
import { MediaByIdentifier } from '../api/mediaController';

jest.mock('axios', () => jest.fn());

test('Test AxiosRequest',async () => {
    const mRes = { status: 200, data: 'fake data' };
    (axios as unknown as jest.Mock).mockResolvedValueOnce(mRes);
    const mock = await MediaByIdentifier('Test');
    expect(mock).toEqual(mRes);
    expect(axios).toHaveBeenCalledTimes(1);
});

mediaController.ts:

import { sendRequest } from './request'
import { AxiosPromise } from 'axios'
import { MediaDto } from './../model/typegen/mediaDto';

const path = '/api/media/'

export const MediaByIdentifier = (identifier: string): AxiosPromise<MediaDto> => {
    return sendRequest(path + 'MediaByIdentifier?identifier=' + identifier, 'get');
}

request.ts:

import axios, { AxiosPromise, AxiosRequestConfig, Method } from 'axios';

const getConfig = (url: string, method: Method, params?: any, data?: any) => {
     const config: AxiosRequestConfig = {
         url: url,
         method: method,
         responseType: 'json',
         params: params,
         data: data,
         headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' },
    }
    return config;
}

export const sendRequest = (url: string, method: Method, params?: any, data?: any): AxiosPromise<any> => {
    return axios(getConfig(url, method, params, data))
}

ts-jest 27.0부터mocked부터ts-jest는 28.0에서 폐지되어 삭제됩니다.공식 매뉴얼에서 확인할 수 있습니다.그래서 대신 써주세요.jest.mocked부에서jest여기 문서입니다.

ts-module에서 조롱된 기능은 28.0에서 폐지되고 삭제됩니다.

예를 들어 다음과 같습니다.

import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';

jest.mock('axios');

// OPTION - 1
const mockedAxios = jest.mocked(axios, true)
// your original `it` block
it('Calls the GET method as expected', async () => {
  const expectedResult: string = 'result';

  mockedAxios.mockReturnValueOnce({ data: expectedResult });
  const result = await myModuleThatCallsAxios.makeGetRequest();

  expect(mockedAxios.get).toHaveBeenCalled();
  expect(result).toBe(expectedResult);
});

최신 Axios(0.21.1)로 업데이트한 후 이런 문제가 발생하였습니다.나는 많은 해결책을 시도해봤지만 아무 성과도 없었다.

회피책:

type axiosTestResponse = (T: unknown) => Promise<typeof T>;

...

it('some example', async () => {
  const axiosObject = {
    data: { items: [] },
    status: 200,
    statusText: 'ok',
    headers: '',
    config: {},
  } as AxiosResponse;

  (Axios.get as axiosTestResponse) = () => Promise.resolve(axiosObject);
});

언급URL : https://stackoverflow.com/questions/51495473/typescript-and-jest-avoiding-type-errors-on-mocked-functions