sourcecode

Jest에서 TypeScript를 사용한 모의 의존 관계

codebag 2023. 2. 27. 22:48
반응형

Jest에서 TypeScript를 사용한 모의 의존 관계

jest.mock TypeScript의 에러를 mockReturnThisOnce)jest.mockmethod)는 이미 입력되어 있기 때문에 의존관계에 존재하지 않습니다.

가 TypeScript에서 해야 요?jest.mock

여기 간단한 예가 있습니다.

의존

const myDep = (name: string) => name;
export default myDep;

테스트.ts

import * as dep from '../depenendency';
jest.mock('../dependency');

it('should do what I need', () => {
  //this throws ts error
  // Property mockReturnValueOnce does not exist on type (name: string)....
  dep.default.mockReturnValueOnce('return')
}

이것은 매우 일반적인 사용 사례라고 생각하기 때문에, 어떻게 타이핑을 해야 할지 잘 모르겠습니다.

과 자신의 캐스팅을 할 수 .test.ts요.

import * as dep from '../dependency';
jest.mock('../dependency');

const mockedDependency = <jest.Mock<typeof dep.default>>dep.default;

it('should do what I need', () => {
  //this throws ts error
  // Property mockReturnValueOnce does not exist on type (name: string)....
  mockedDependency.mockReturnValueOnce('return');
});

는 TS가 .jest.mock('../dependency'); " " " "dep활자 주조법을 사용해야 합니다. asdepa a is is is with with with with with with with with with with with with is is is is is is is is is is is is is.typeof dep.default.

다음은 Jest와 TS를 사용하는 동안 발견한 몇 가지 유용한 패턴입니다.

가져온 요소가 클래스인 경우 다음과 같은 유형을 사용할 필요가 없습니다.

import { SomeClass } from './SomeClass';

jest.mock('./SomeClass');

const mockedClass = <jest.Mock<SomeClass>>SomeClass;

이 솔루션은 일부 노드 네이티브모듈을 시뮬레이션해야 할 경우에도 유용합니다.

import { existsSync } from 'fs';

jest.mock('fs');

const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;

jajest 자동모크를 사용하지 않고 수동모크를 만들고 싶은 경우

import TestedClass from './TestedClass';
import TestedClassDependency from './TestedClassDependency';

const testedClassDependencyMock = jest.fn<TestedClassDependency>(() => ({
  // implementation
}));

it('Should throw an error when calling playSomethingCool', () => {
  const testedClass = new TestedClass(testedClassDependencyMock());
});

testedClassDependencyMock()는 조롱된 .TestedClassDependency 또는 중 일 수 있습니다.

여기설명대로 도우미를 사용합니다.

// foo.spec.ts
import { foo } from './foo'
jest.mock('./foo')

// here the whole foo var is mocked deeply
const mockedFoo = jest.mocked(foo, true)

test('deep', () => {
  // there will be no TS error here, and you'll have completion in modern IDEs
  mockedFoo.a.b.c.hello('me')
  // same here
  expect(mockedFoo.a.b.c.hello.mock.calls).toHaveLength(1)
})

test('direct', () => {
  foo.name()
  // here only foo.name is mocked (or its methods if it's an object)
  expect(jest.mocked(foo.name).mock.calls).toHaveLength(1)
})

TypeScript 버전 3.x 및 4.x에 대해 테스트된 두 가지 솔루션이 있으며, 둘 다 원하는 기능을 제공합니다.

1) 농담을 사용한다.기능 예시

import * as dep from './dependency';

jest.mock('./dependency');

const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;

2) 농담을 사용합니다.모의

import * as dep from './dependency';

jest.mock('./dependency');

const mockMyFunction = dep.default as jest.Mock;

이 두 솔루션 사이에는 차이가 없습니다.두 번째 것이 더 짧기 때문에 나는 그것을 사용할 것을 제안한다.

두 캐스팅 솔루션 모두 농담 모의 함수를 호출할 수 있습니다.mockMyFunctionmockReturnValue ★★★★★★★★★★★★★★★★★」mockResolvedValue https://jestjs.io/docs/en/mock-function-api.htmlhttpsjestjs.io/docs/en/.html

mockMyFunction.mockReturnValue('value');

mockMyFunction대로 할 수 있다

expect(mockMyFunction).toHaveBeenCalledTimes(1);

def 타입 바로 위에 있는 @types/jest/index.d.ts의 패턴을 사용합니다(515행).

import { Api } from "../api";
jest.mock("../api");

const myApi: jest.Mocked<Api> = new Api() as any;
myApi.myApiMethod.mockImplementation(() => "test");

★★★★★★★as jest.Mock

단순히 기능만 부여하면jest.Mock과가있있 있있있다다

(dep.default as jest.Mock).mockReturnValueOnce('return')

as jest.Mock에는 아무것도 없습니다.

을 가장 default을 ts-jest로 할 수 .jest.Mock.

코드:

import myDep from '../dependency' // No `* as` here

jest.mock('../dependency')

it('does what I need', () => {
  // Only diff with pure JavaScript is the presence of `as jest.Mock`
  (myDep as jest.Mock).mockReturnValueOnce('return')

  // Call function that calls the mocked module here

  // Notice there's no reference to `.default` below
  expect(myDep).toHaveBeenCalled()
})

이점:

  • 에서는 을 .default- 실제 을 대신합니다.실제로 내보낸 함수 이름을 대신 참조합니다.
  • 이름 있는 수출품을 조롱할 때도 같은 기술을 사용할 수 있습니다.
  • 아니요.* as수입 명세서에 기재되어 있습니다.
  • 복잡한 캐스팅은 사용하지 않습니다.typeof키워드,
  • 같은 추가 의존이 없다mocked.

다음은 jeast@24.8.0과 ts-jest@24.0.2에 대해 수행한 작업입니다.

출처:

class OAuth {

  static isLogIn() {
    // return true/false;
  }

  static getOAuthService() {
    // ...
  }
}

테스트:

import { OAuth } from '../src/to/the/OAuth'

jest.mock('../src/utils/OAuth', () => ({
  OAuth: class {
    public static getOAuthService() {
      return {
        getAuthorizationUrl() {
          return '';
        }
      };
    }
  }
}));

describe('createMeeting', () => {
  test('should call conferenceLoginBuild when not login', () => {
    OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
      return false;
    });

    // Other tests
  });
});

디폴트 이외의 클래스와 스태틱한 메서드를 다음과 같이 모의합니다.

jest.mock('../src/to/the/OAuth', () => ({
  OAuth: class {
    public static getOAuthService() {
      return {
        getAuthorizationUrl() {
          return '';
        }
      };
    }
  }
}));

여기 당신의 클래스 유형에서 로의 유형 변환이 있을 것입니다.jest.MockedClass아니면 그런 비슷한 것.하지만 결국엔 항상 오류가 생기죠.그래서 직접 사용해보니 효과가 있었어요.

test('Some test', () => {
  OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
    return false;
  });
});

그런데 함수라면 조롱하고 유형대화를 할 수 있어요.

jest.mock('../src/to/the/Conference', () => ({
  conferenceSuccessDataBuild: jest.fn(),
  conferenceLoginBuild: jest.fn()
}));
const mockedConferenceLoginBuild = conferenceLoginBuild as 
jest.MockedFunction<
  typeof conferenceLoginBuild
>;
const mockedConferenceSuccessDataBuild = conferenceSuccessDataBuild as 
jest.MockedFunction<
  typeof conferenceSuccessDataBuild
>;

최신 농담은 농담으로 쉽게 할 수 있게 해준다.

import * as dep from '../dependency';

jest.mock('../dependency');

const mockedDependency = jest.mocked(dep);

it('should do what I need', () => {
  mockedDependency.mockReturnValueOnce('return');
});

제스트 기준24.9.0Class/Object/Function과 Jest 속성을 모두 시뮬레이션하고 올바르게 입력할 수 있는 방법은 다음과 같습니다.

jest.Mocked 기능

jeast.Mocked 클래스

우리가 타이핑된 모크를 원하는 것은 모조된 오브젝트 타입이 모조된 오브젝트 타입과 제스트 모크의 타입의 결합을 포함하고 있다는 것입니다.

import foo from 'foo';
jest.mock('foo');

const mockedFoo = foo as jest.MockedFunction<typeof foo>;
// or: const mockedFooClass = foo as jest.MockedClass<typeof FooClass>;


mockedFoo.mockResolvedValue('mockResult');

// Or:
(mockedFoo.getSomething as jest.MockedFunction<typeof mockedFoo.getSomething>).mockResolvedValue('mockResult');

보시다시피, 필요한 것을 수동으로 캐스트 할 수도 있고, 모든 것을 타이핑/캐스팅하기 위해 모든 foo의 속성/메서드를 통과할 수 있는 무언가가 필요합니다.

그러기 위해서는(심층 모의 유형) Jest에 도입된jest.mocked()사용합니다.27.4.0

import foo from 'foo';
jest.mock('foo');

const mockedFoo = jest.mocked(foo, true); 

mockedFoo.mockImplementation() // correctly typed
mockedFoo.getSomething.mockImplementation() // also correctly typed

이것은 에서 찾았습니다.@types/jest:

/**
  * Wrap a function with mock definitions
  *
  * @example
  *
  *  import { myFunction } from "./library";
  *  jest.mock("./library");
  *
  *  const mockMyFunction = myFunction as jest.MockedFunction<typeof myFunction>;
  *  expect(mockMyFunction.mock.calls[0][0]).toBe(42);
*/

주의: 실행 시const mockMyFunction = myFunction그 다음에 뭐랄까mockFunction.mockReturnValue('foo'), 당신은 변화하고 있습니다.myFunction뿐만 아니라.

출처 : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jest/index.d.ts#L1089

Artur Görski의 최고 등급 솔루션은 이전 TS 및 Jest에서는 작동하지 않습니다.Discured Class 사용

import SoundPlayer from '../sound-player';

jest.mock('../sound-player'); // SoundPlayer is now a mock constructor

const SoundPlayerMock = SoundPlayer as jest.MockedClass<typeof SoundPlayer>;

최근 라이브러리는 babel 플러그인으로 이 문제를 해결합니다.https://github.com/userlike/joke

예를 들어:

import { mock, mockSome } from 'userlike/joke';

const dep = mock(import('./dependency'));

// You can partially mock a module too, completely typesafe!
// thisIsAMock has mock related methods
// thisIsReal does not have mock related methods
const { thisIsAMock, thisIsReal } = mockSome(import('./dependency2'), () => ({ 
  thisIsAMock: jest.fn() 
}));

it('should do what I need', () => {
  dep.mockReturnValueOnce('return');
}

주의해 주세요dep그리고.mockReturnValueOnce완전 안전합니다.위에서 tsserver는 다음을 인식하고 있습니다.depencencyImport되어 할당되었습니다.dep따라서 tsserver가 지원하는 모든 자동 리팩터링도 작동합니다.

메모: 저는 라이브러리를 관리합니다.

이것은 추악합니다.사실 이 추악함에서 벗어나는 것이 제가 이 질문을 본 이유이기도 하지만 모듈 모의에서 강력한 타이핑을 얻으려면 다음과 같은 작업을 할 수 있습니다.

const myDep = (require('./dependency') as import('./__mocks__/dependency')).default;

jest.mock('./dependency');

필요한 것을 확인해 주세요.'./dependency'직접 모의하는 것보다 두 가지 다른 인스턴스화를 얻을 수 있습니다.

이 정도면 충분했습니다.

let itemQ: queueItemType
jest.mock('../dependency/queue', () => {
    return {
        add: async (item: queueItemType, ..._args: any) => {
            // then we can use the item that would be pushed to the queue in our tests
            itemQ = item
            return new Promise(resolve => {
                resolve('Mocked')
            })
        },
    }
})

그런 다음 add 메서드가 호출될 때마다 위의 코드를 큐에 푸시하지 않고 실행합니다.

2.에서는 TypeScript 2.8에서 이렇게 할 수.ReturnType:

import * as dep from "./depenendency"

jest.mock("./dependency")

const mockedDependency = <jest.Mock<ReturnType<typeof dep.default>>>dep.default

it("should do what I need", () => {
  mockedDependency.mockReturnValueOnce("return")
})

언급URL : https://stackoverflow.com/questions/48759035/mock-dependency-in-jest-with-typescript

반응형