ejemplos attribute javascript unit-testing mocking jestjs

javascript - attribute - Cómo cambiar la implementación simulada en base a una sola prueba



title html css (3)

Poco tarde a la fiesta, pero si alguien más está teniendo problemas con esto.

Utilizamos TypeScript, ES6 y babel para el desarrollo nativo reactivo.

Por lo general, __mocks__ módulos NPM externos en el directorio raíz __mocks__ .

Quería anular una función específica de un módulo en la clase Auth de aws-amplify para una prueba específica.

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

Me gustaría cambiar la implementación de una dependencia simulada en base a una sola prueba extendiendo el comportamiento de la simulación predeterminada y volviendo a la implementación original cuando se ejecuta la siguiente prueba.

Más brevemente esto es lo que estoy tratando de lograr:

  1. simulacro de dependencia
  2. Cambiar / extender la implementación simulada en una sola prueba.
  3. volver a la simulación original cuando se ejecuta la siguiente prueba

Actualmente estoy usando Jest v21 .

Aquí es cómo se vería una típica prueba de 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 eeffects }); it(''should revert back to default myMockedModule mock'', () => { myMockedModule.a(); // === true myMockedModule.b(); // === true }); });

Probé algunas estrategias, pero no encontré ninguna solución que pudiera definir satisfactoria.

1 - mockFn.mockImplementationOnce(fn)

pros

  • Vuelve a la implementación original después de la primera llamada.

contras

  • Se romperá si la prueba llama b más veces
  • No volverá a la implementación original hasta que no se llame a b (se filtra en la siguiente prueba)

código:

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 (nombre de módulo, fábrica, opciones)

pros

  • Se vuelve a imitar explícitamente en cada prueba

contras

  • No se puede definir una implementación simulada predeterminada para todas las pruebas
  • No se puede extender una implementación predeterminada forzando a volver a declarar cada método simulado

código:

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 - Simulación manual con métodos de establecimiento (como se explica here )

pros

  • Control total sobre resultados burlados.

contras

  • Lote de código repetitivo
  • Difícil de mantener a largo plazo

código:

__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)

contras

  • No puedo revertir mockImplementation al valor de retorno mockImplementation original, por lo tanto afectando las siguientes pruebas

código:

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 the original mocked value? });

Gracias de antemano por cualquier entrada / sugerencia!


Un buen patrón para la prueba de escritura es crear una función de configuración de fábrica que devuelva los datos que necesita para probar el módulo actual.

A continuación se muestra un código de ejemplo que sigue a su segundo ejemplo, aunque permite la provisión de valores predeterminados y de anulación de manera reutilizable.

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


Utilice mockFn.mockImplementation(fn) .

Ponga la implementación predeterminada en el beforeEach . El simulacro se reiniciará antes de cada prueba.

Para anular, use mockImplementation en la prueba.

Esto anulará el comportamiento del simulacro para cualquiera / todas las llamadas en la prueba, y será sobrescrito por la implementación de beforeEach antes de la siguiente prueba.

Por ejemplo:

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