Come modificare l'implementazione fittizia su una singola base di test [Jestjs]


86

Mi piacerebbe cambiare l'implementazione di una dipendenza deriso su una base per basi di prova unico per l'estensione del finto di default 's comportamento e tornando indietro per l'implementazione originale quando il prossimo esegue test.

Più brevemente questo è ciò che sto cercando di ottenere:

  1. finta dipendenza
  2. modificare / estendere l'implementazione fittizia in un singolo test
  3. torna al mock originale quando viene eseguito il test successivo

Attualmente sto usando Jest v21.

Ecco come sarebbe un tipico test 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
  });
});

Ecco cosa ho provato finora:


1 - mockFn.mockImplementationOnce (fn)

professionisti

  • Torna all'implementazione originale dopo la prima chiamata

contro

  • Si interrompe se il test chiama bpiù volte
  • Non torna all'implementazione originale fino a quando bnon viene chiamato (fuoriuscita nel test successivo)

codice:

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 (moduleName, factory, options)

professionisti

  • Ridefinisce esplicitamente ad ogni test

contro

  • Impossibile definire l'implementazione fittizia predefinita per tutti i test
  • Impossibile estendere l'implementazione predefinita costringendo a dichiarare nuovamente ogni metodo deriso

codice:

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 - Derisione manuale con metodi setter (come spiegato qui )

professionisti

  • Pieno controllo sui risultati falsificati

contro

  • Lotto codice boilerplate
  • Difficile da mantenere a lungo termine

codice:

__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 (object, methodName)

contro

  • Non riesco a tornare al mockImplementationvalore di ritorno originale deriso, influenzando quindi i test successivi

codice:

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?
});

Bello. Ma come si fa l'opzione 2 per un modulo npm come "@ private-repo / module"? La maggior parte degli esempi che vedo hanno percorsi relativi? Funziona anche per i moduli installati?
mrbinky3000

Risposte:


47

Un buon modello per la scrittura di test è creare una funzione di setup factory che restituisca i dati necessari per testare il modulo corrente.

Di seguito è riportato un codice di esempio che segue il secondo esempio, sebbene consenta la fornitura di valori predefiniti e di sostituzione in modo riutilizzabile.

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)
  });
});

40

Vanilla JS

Usa 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 */ });
  // ...
});

Dattiloscritto

Per evitare che il messaggio mockImplementation non sia una proprietà di funcToMock , dovrai specificare il tipo, ad esempio cambiando la riga superiore dall'alto al seguente:

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

Una domanda che affronta questo problema può essere trovata qui: jest typescript proprietà mock non esiste su type


21

Un po 'tardi per la festa, ma se qualcun altro ha problemi con questo.

Usiamo TypeScript, ES6 e babel per lo sviluppo nativo di reazione.

Di solito prendiamo in giro i moduli NPM esterni nella __mocks__directory principale .

Volevo sovrascrivere una funzione specifica di un modulo nella classe Auth di aws-amplify per un test specifico.

    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();
    });

Gist: https://gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2

Tutorial: https://medium.com/p/b4ac52a005d#19c5

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.