[javascript] 단일 테스트 단위로 모의 구현을 변경하는 방법 [Jestjs]

내가하고 싶은 조롱 의존성의 구현을 변경 당에 단일 시험 기준 에 의해 기본 모형 확장 의 동작을하고 다시 되 돌리는 원래 구현 다음 테스트 실행한다.

더 간단히 말하자면 이것이 내가 달성하려는 것입니다.

  1. 모의 의존성
  2. 단일 테스트에서 모의 구현 변경 / 확장
  3. 다음 테스트가 실행되면 원래 모의로 되돌립니다.

나는 현재 Jest v21.

일반적인 Jest 테스트는 다음과 같습니다.

__mocks__/myModule.js

const myMockedModule = jest.genMockFromModule('../myModule');

myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);

export default myMockedModule;

__tests__/myTest.js

import myMockedModule from '../myModule';

// Mock myModule
jest.mock('../myModule');

beforeEach(() => {
  jest.clearAllMocks();
});

describe('MyTest', () => {
  it('should test with default mock', () => {
    myMockedModule.a(); // === true
    myMockedModule.b(); // === true
  });

  it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
    // Extend change mock
    myMockedModule.a(); // === true
    myMockedModule.b(); // === 'overridden'
    // Restore mock to original implementation with no side effects
  });

  it('should revert back to default myMockedModule mock', () => {
    myMockedModule.a(); // === true
    myMockedModule.b(); // === true
  });
});

지금까지 시도한 내용은 다음과 같습니다.


1- mockFn.mockImplementationOnce (fn)

찬성

  • 첫 번째 호출 후 원래 구현으로 되돌립니다.

단점

  • 테스트가 b여러 번 호출되면 중단됩니다.
  • b호출되지 않을 때까지 원래 구현으로 되 돌리지 않습니다 (다음 테스트에서 유출).

암호:

it('should override myModule.b mock result (and leave the other methods untouched)', () => {

  myMockedModule.b.mockImplementationOnce(() => 'overridden');

  myModule.a(); // === true
  myModule.b(); // === 'overridden'
});

2- jest.doMock (모듈 이름, 공장, 옵션)

찬성

  • 모든 테스트에서 명시 적으로 다시 조롱

단점

  • 모든 테스트에 대한 기본 모의 구현을 정의 할 수 없습니다.
  • 모의 메서드를 다시 선언하도록 기본 구현을 확장 할 수 없습니다.

암호:

it('should override myModule.b mock result (and leave the other methods untouched)', () => {

  jest.doMock('../myModule', () => {
    return {
      a: jest.fn(() => true,
      b: jest.fn(() => 'overridden',
    }
  });

  myModule.a(); // === true
  myModule.b(); // === 'overridden'
});

3-setter 메서드를 사용한 수동 조롱 ( 여기에 설명 된대로 )

찬성

  • 모의 결과에 대한 완전한 제어

단점

  • 많은 상용구 코드
  • 장기간 유지하기 어려움

암호:

__mocks__/myModule.js

const myMockedModule = jest.genMockFromModule('../myModule');

let a = true;
let b = true;

myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);

myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
  a = true;
  b = true;
};
export default myMockedModule;

__tests__/myTest.js

it('should override myModule.b mock result (and leave the other methods untouched)', () => {
  myModule.__setB('overridden');

  myModule.a(); // === true
  myModule.b(); // === 'overridden'

  myModule.__reset();
});

4- jest.spyOn (객체, 메소드 이름)

단점

  • mockImplementation원래 모의 반환 값으로 되돌릴 수 없으므로 다음 테스트에 영향을 미칩니다.

암호:

beforeEach(() => {
  jest.clearAllMocks();
  jest.restoreAllMocks();
});

// Mock myModule
jest.mock('../myModule');

it('should override myModule.b mock result (and leave the other methods untouched)', () => {

  const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');

  myMockedModule.a(); // === true
  myMockedModule.b(); // === 'overridden'

  // How to get back to original mocked value?
});



답변

테스트 작성을위한 좋은 패턴은 현재 모듈을 테스트하는 데 필요한 데이터를 반환하는 설정 팩토리 함수를 만드는 것입니다.

다음은 두 번째 예제를 따르는 몇 가지 샘플 코드이지만 재사용 가능한 방식으로 기본값을 제공하고 값을 재정의 할 수 있습니다.

const spyReturns = returnValue => jest.fn(() => returnValue);

describe("scenario", () => {
  const setup = (mockOverrides) => {
    const mockedFunctions =  {
      a: spyReturns(true),
      b: spyReturns(true),
      ...mockOverrides
    }
    return {
      mockedModule: jest.doMock('../myModule', () => mockedFunctions)
    }
  }

  it("should return true for module a", () => {
    const { mockedModule } = setup();
    expect(mockedModule.a()).toEqual(true)
  });

  it("should return override for module a", () => {
    const EXPECTED_VALUE = "override"
    const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)});
    expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
  });
});


답변

바닐라 JS

mockFn.mockImplementation (fn)을 사용하십시오 .

import { funcToMock } from './somewhere';
jest.mock('./somewhere');

beforeEach(() => {
  funcToMock.mockImplementation(() => { /* default implementation */ });
});

test('case that needs a different implementation of funcToMock', () => {
  funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
  // ...
});

TypeScript

Vanilla JS 솔루션 외에 :

mockImplementation 메시지가 funcToMock의 속성이 아닌 것을 방지하려면 유형을 지정해야합니다. 예를 들어 상단 행을 위에서 다음과 같이 변경합니다.

import { (funcToMock as jest.Mock) } from './somewhere';

이 문제를 다루는 질문은 여기에서 찾을 수 있습니다 : jest typescript property mock does not exist on type


답변

파티에 조금 늦었지만 다른 사람이 이것에 문제가 있다면.

반응 네이티브 개발을 위해 TypeScript, ES6 및 babel을 사용합니다.

우리는 일반적으로 루트 __mocks__디렉터리 에서 외부 NPM 모듈을 모의 합니다.

특정 테스트를 위해 aws-amplify의 Auth 클래스에있는 모듈의 특정 기능을 재정의하고 싶었습니다.

    import { Auth } from 'aws-amplify';
    import GetJwtToken from './GetJwtToken';
    ...
    it('When idToken should return "123"', async () => {
      const spy = jest.spyOn(Auth, 'currentSession').mockImplementation(() => ({
        getIdToken: () => ({
          getJwtToken: () => '123',
        }),
      }));

      const result = await GetJwtToken();
      expect(result).toBe('123');
      spy.mockRestore();
    });

요점 :
https://gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2

튜토리얼 :
https://medium.com/p/b4ac52a005d#19c5


답변