Tek test temelinde sahte uygulama nasıl değiştirilir [Jestjs]


96

İsterdim bir alay bağımlılık uygulanmasını değiştirmek başına üzerinde tek bir test temelinde tarafından varsayılan taklidi uzanan 'ın davranış ve geri dönerek orjinal uygulanması sonraki test yürütür için.

Daha kısaca başarmaya çalıştığım şey bu:

  1. sahte bağımlılık
  2. tek bir testte sahte uygulamayı değiştir / genişlet
  3. bir sonraki test yürütüldüğünde orijinal modele geri dönün

Şu anda kullanıyorum Jest v21.

Tipik bir Jest testi şöyle görünür:

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

İşte şimdiye kadar denediğim şey:


1 - mockFn.mockImplementationOnce (fn)

artıları

  • İlk aramadan sonra orijinal uygulamaya geri döner

Eksileri

  • Test bbirden çok kez ararsa bozulur
  • bÇağrılana kadar orijinal uygulamaya geri dönmez (bir sonraki testte dışarı sızar)

kod:

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, fabrika, seçenekler)

artıları

  • Her testte açıkça yeniden alay

Eksileri

  • Tüm testler için varsayılan sahte uygulama tanımlanamaz
  • Varsayılan uygulama, alay edilen her yöntemi yeniden bildirmeye zorlamak için genişletilemez

kod:

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 - Ayarlayıcı yöntemlerle manuel alay ( burada açıklandığı gibi )

artıları

  • Alay edilen sonuçlar üzerinde tam kontrol

Eksileri

  • Çok sayıda standart kod
  • Uzun vadede bakımı zor

kod:

__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 (nesne, yöntemAdı)

Eksileri

  • Ben Geri döndürme geri olabilir mockImplementation, bu nedenle sonraki testler özgün alay dönüş değerine etki eden

kod:

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

Güzel. Ancak '@ private-repo / module' gibi bir npm modülü için 2. seçeneği nasıl yaparsınız? Gördüğüm çoğu örneğin göreceli yolları var mı? Bu, kurulu modüller için de çalışıyor mu?
mrbinky3000

Yanıtlar:


54

Test yazmak için güzel bir model, mevcut modülü test etmek için ihtiyacınız olan verileri döndüren bir fabrika kurulum işlevi oluşturmaktır.

Aşağıda, ikinci örneğinizi izleyen bazı örnek kodlar verilmiştir, ancak yeniden kullanılabilir bir şekilde varsayılan değerlerin sağlanmasına ve değerlerin geçersiz kılınmasına izin verilmektedir.

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

42

Vanilya JS

MockFn.mockImplementation (fn) kullanın .

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 çözümüne ek olarak:

MockImplementation mesajının funcToMock özelliği olmamasını önlemek için , örneğin üst satırı yukarıdan aşağıdakine değiştirerek türü belirtmeniz gerekir:

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

Bu sorunu ele alan bir soru burada bulunabilir: jest typcript özelliği mock, type üzerinde mevcut değil


23

Partiye biraz geç, ama eğer başka biri bununla ilgili sorun yaşıyorsa.

React-native geliştirme için TypeScript, ES6 ve babel kullanıyoruz.

Genellikle kök __mocks__dizinde harici NPM modülleriyle alay ederiz .

Belirli bir test için aws-amplify'nin Auth sınıfındaki bir modülün belirli bir işlevini geçersiz kılmak istedim.

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

Ana bilgi: https://gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2

Öğretici: https://medium.com/p/b4ac52a005d#19c5

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.