<p>pabrik jest.mock tidak berfungsi di dalam tes</p>

Dibuat pada 12 Jan 2017  ·  38Komentar  ·  Sumber: facebook/jest

Apakah Anda ingin meminta fitur atau melaporkan bug ?
Serangga

Apa perilaku saat ini?

Tampaknya cara membuat tiruan dengan pabrik tidak berfungsi di dalam test atau it . Ini hanya berfungsi ketika tiruan didefinisikan pada tingkat root file.

Inilah contoh tiruan saya:

jest.mock('services/feature', () => ({
    isEnabled: () => true
}));

Apa perilaku yang diharapkan?

Mengejek file di dalam tes seharusnya berhasil.

Harap berikan konfigurasi Jest Anda yang tepat dan sebutkan Jest, node, versi yarn/npm dan sistem operasi Anda.

Jest 18.0.0, Node 7.4, macOS

Confirmed Discussion

Komentar yang paling membantu

Untuk mengubah nilai pengembalian tiruan di antara pengujian, Anda dapat melakukan sesuatu seperti ini:

jest.mock('whatever');

// Get the mock function
const whatever = require('whatever');

test('test 1', () => {
  whatever.mockImplementation(() => 'hello');
});

test('test 2', () => {
  whatever.mockImplementation(() => 'world');
});

Semua 38 komentar

Panggilan jest.mock secara otomatis diangkat ke atas file dengan transformasi babel-jest. Anda dapat menghilangkan perilaku ini dengan jest.doMock . Sudahkah Anda mencoba itu?

Hal yang sama dengan doMock .

Di dokumen, saya bisa membaca

Catatan: Saat menggunakan babel-jest , panggilan untuk mengejek akan secara otomatis diangkat ke bagian atas blok kode. Gunakan doMock jika Anda ingin menghindari perilaku ini secara eksplisit.

Tapi... Tes adalah blok kode, kan? Jadi dalam kasus saya, saya tidak berharap untuk melihat perbedaan.

Berikut tes lengkapnya

it('renders with the enabled feature', () => {
  jest.mock('services/feature', () => ({
      isEnabled: () => true
  }));

  const component = renderer.create(
      <MyComponent />
  );

  const tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

Bisakah Anda memberikan repro ini di repositori GH?

Tentu. Ini dia: https://github.com/tleunen/jest-issue-2582

Kedua tes merender "Dinonaktifkan" meskipun salah satunya memiliki tiruan untuk membuat "Diaktifkan" sebagai gantinya.
Lihat ini:
https://github.com/tleunen/jest-issue-2582/blob/master/src/MyComponent.js
https://github.com/tleunen/jest-issue-2582/blob/master/src/__tests__/MyComponent.spec.js

Terima kasih.

Adakah saran @cpojer untuk masalah ini?
Saya memiliki beberapa tes dalam file yang sama dan saya ingin memiliki tanggapan tiruan yang berbeda untuk masing-masing tes.

Senang saya menemukan masalah ini, saya bingung mengapa jest.mock() tidak berfungsi dalam lingkup describe . Memindahkannya ke atas (di bawah impor saya di file pengujian) dan berfungsi.

Bagi saya ini juga berlaku untuk jest.mock() tanpa pabrik, menggunakan folder __mocks__ berisi file tiruan.

--edit

Jelas perlu untuk mengangkat pernyataan jest.mock() sebelum pernyataan impor. Namun @tleunen , ini mungkin berarti tidak mungkin untuk mengejek file yang sama lebih dari sekali, dengan respons yang berbeda. Mungkin Anda paling baik dilayani dengan membuat fungsi pabrik lebih dinamis, sehingga dapat memberikan Anda hasil yang berbeda di setiap kasus pengujian.

Dalam pikiran saya akan lebih eksplisit jika jest.mock() selalu diletakkan di luar blok describe dan it . Tetapi ini kemudian harus dinyatakan dengan jelas dalam dokumen

Jadi jest.mock sedang diangkat ke ruang lingkup fungsi, itu sebabnya itu tidak akan bekerja dengan require s (dan jelas bukan import s yang diangkat ke ruang lingkup modul) jika Anda menyebutnya di dalam fungsi selain describe (yang diperlakukan secara khusus oleh Jasmine).
Panggilan jest.mock akan diangkat ke atas fungsi itu sendiri (bukan modul), itu sebabnya itu tidak akan berfungsi seperti yang Anda harapkan.

Umumnya kami menyarankan untuk mengatur tiruan yang berbeda di beforeEach dan afterEach jika Anda ingin mereka berbeda di seluruh kasus uji.

@cpojer dapat menguraikan ini secara rinci, dan jika kita ingin mengangkat panggilan ke cakupan atas.

Ini karena Anda memerlukan modul Anda saat modul diinisialisasi (menggunakan impor). jest.mock dipanggil belakangan. Cara mengatasinya adalah:

beforeEach(() => { // or the specific test
  jest.mock('MyModule', () => …);
  const MyModule = require('MyModule');
  …
});

dll.

Jika Anda melakukan ini di beforeEach, saya tidak jelas bagaimana Anda membedakan tes (jadi bagaimana Anda akan memberikan tiruan yang berbeda untuk setiap tes?)

Menempatkannya di dalam tes itu sendiri tentu saja berhasil.

Bisakah Anda meneruskan modul tiruan di dalam komponen yang diuji?

Bagaimana jika saya tidak mengimpor/memerlukan file yang ingin saya tiru (misalnya ketergantungan dari file lain yang saya impor) tetapi saya ingin file tersebut dicakup ke blok deskripsi/itu? Atau bahkan jika saya ingin mengejek secara berbeda untuk tes beforeEach/beforeAll? Apakah kasus-kasus itu mungkin?

// A.js depends on B.js
import A from './A';

describe('myTest', () => {

    describe('myFirstScope', () => {
        beforeAll(() => {
            jest.mock('./B', () => ({
                myFirstMethod: jest.fn(),
            }));
        });

        // tests here
    });

    describe('mySecondScope', () => {
        beforeAll(() => {
            jest.mock('./B', () => ({
                mySecondMethod: jest.fn(),
            }));
        });

        // tests here
    });
});

Dalam hal ini, Anda perlu meminta A setelah mengejek B. (Tidak menggunakan import , tetapi require ).

membutuhkan A setelah mengejek B

tidak berhasil untuk saya, masih melihat tiruan asli B melewati hasilnya

@GoldAnna apakah Anda sudah menemukan solusi untuk masalah ini?

@alayor saya belum

Sering kali saya mengalami masalah ini, saya sekarang yakin saya tidak menguji dengan benar, tidak menggunakan jest seperti yang dimaksudkan penulis, atau kombinasi keduanya. Bukti lebih lanjut adalah bahwa hampir tidak ada contoh terkait tiruan dalam dokumentasi jest tampak seperti contoh dunia nyata bagi saya...mungkin begitu dan pendekatan saya mungkin salah.

Yang mengatakan, berikut ini berfungsi untuk saya, dan semua tes berikut lulus. Perhatikan bahwa untuk kembali ke versi asli ModuleB , saya harus memanggil jest.resetModules() dan jest.unmock('./moduleB') ...urutannya tidak penting.

// Module A
const ModuleB = require('./moduleB');
const ModuleA = function() {
  this.title = new ModuleB().title;
  return this;
};
module.exports = ModuleA;

// Module B
const ModuleB = function() {
  this.title = 'Module B - Original'
  return this;
};
module.exports = ModuleB;

// Tests
describe('Jest a few tests', () => {
  it('should do something', () => {
    jest.resetModules();
    jest.mock('./moduleB', () => function() {
      this.title = 'Module B - Mock 1'
      return this;
    });
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Mock 1');
  });

  it('should do something else', () => {
    jest.resetModules();
    jest.mock('./moduleB', () => function() {
      this.title = 'Module B - Mock 2'
      return this;
    });
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Mock 2');
  });

  it('should do something original', () => {
    jest.resetModules();
    jest.unmock('./moduleB');
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Original');
  });
});

Hai,

Tidak ada di sini bekerja untuk saya.
Adakah yang bisa menjelaskan mengapa tidak mungkin menggunakan jest.mock di dalamnya?

Terima kasih

Saya pikir ini masih merupakan masalah yang mungkin harus dibuka kembali sebagai permintaan fitur. Saya ingin menulis tes secara terpisah. Membuang barang-barang di folder tiruan atau memasang kembali dengan beforeEach biasanya berakhir dengan laci sampah tiruan/instantiasi data aneh yang terseret ke dalam setiap pengujian. Saya ingin menulis tiruan kecil dan membuat ujian kecil.

Kami tidak memiliki cara nyata untuk mengisolasi pengujian individual (dengan mempertimbangkan test.concurrent ). Jika kami mengadopsi API yang mirip dengan tap atau ava, itu mungkin, tapi saya rasa itu tidak mungkin dengan batasan yang diberlakukan oleh API global saat ini. Sangat senang terbukti salah!

Berjuang dengan beberapa metode di sini untuk memperbaiki tes yang sebelumnya ditulis dalam moka dan proxyquire, berakhir dengan memisahkan tes menjadi file yang berbeda untuk tiruan yang berbeda.

@gcox Sudahkah Anda mencoba mengejek (dan membutuhkan moduleA setelahnya) di tingkat atas modul dan kemudian mengubah implementasi tiruan untuk setiap tes yang membutuhkan perilaku berbeda? Anda dapat menggunakan mockImplementation untuk melakukannya. Beginilah cara kami menyelesaikan ini di suite pengujian kami.

@antgonzales Saya pikir itu sulit dilakukan jika impor modul diangkat ke atas modul. Memodifikasi referensi modul yang diimpor sebelumnya tampaknya tidak sepele hingga mustahil di node.js.

@jkomusin Pasti. Bukan itu yang diminta OP, IMO. Saya yakin mereka bertanya, khususnya, "Bagaimana cara memaksa require('whatever') untuk mengembalikan tiruan yang berbeda di beberapa tes yang berdekatan daripada objek yang sama?".

Untuk mengubah nilai pengembalian tiruan di antara pengujian, Anda dapat melakukan sesuatu seperti ini:

jest.mock('whatever');

// Get the mock function
const whatever = require('whatever');

test('test 1', () => {
  whatever.mockImplementation(() => 'hello');
});

test('test 2', () => {
  whatever.mockImplementation(() => 'world');
});

@gcox answer berhasil untuk saya, tetapi @SimenB juga berhasil, dan jauh lebih sederhana!

@rafaeleyng tetapi @SimenB tidak berfungsi jika apa yang Anda ekspor dari modul bukan fungsi ...

Contoh @gcox berisi sebagian besar informasi yang telah saya cari di dokumen selama beberapa jam terakhir. Saya menyarankan bahwa itu harus dimasukkan dalam dokumentasi resmi yang saat ini sangat jarang.

@schhumannd benar. Tolong buat dokumentasi resmi lebih jelas dan tajam.

PR selalu menyambut baik peningkatan dokumen

Contoh modul berdasarkan
https://github.com/facebook/jest/issues/2582#issuecomment -378677440 ❤️

Heya, temukan ini melalui masalah tertaut dan saya menemukan jawabannya:

jest.mock('child_process')
const childProcess = require('child_process')

describe('foo', () => {
  test('bar', () => {
    childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
    // code that itself requires child_process
    expect(childProcess.execSync.mock.results[0]).toEqual('wibble')
  })

  test('baz', () => {
    childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
    // code that itself requires child_process
    expect(childProcess.execSync.mock.results[0]).toEqual('wobble')
  })
})

Jika Anda perlu meniru beberapa fungsi/metode pada kode yang diperlukan, Anda perlu mengaturnya secara terpisah daripada menggunakan pabrik saat Anda melakukannya secara global.

Jika Anda menyukai saya hanya membutuhkan satu fungsi, Anda dapat menyederhanakan semuanya:

jest.mock('child_process')
const { execSync } = require('child_process')

describe('foo', () => {
  test('bar', () => {
    execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
    // code that itself requires child_process
    expect(execSync.mock.results[0]).toEqual('wibble')
  })

  test('baz', () => {
    execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
    // code that itself requires child_process
    expect(execSync.mock.results[0]).toEqual('wobble')
  })
})

bagaimana dengan mengejek dependensi non fungsi seperti file json, atau konstanta yang dipetakan. Tolong buat dokumentasi lebih jelas tentang cara menangani ini...

@gcox Solusi Anda adalah satu-satunya yang saya temukan ketika modul yang diimpor yang sedang diuji mengimpor modul lain yang saya buat tiruan manualnya dalam folder __mocks__ .

Misalnya, file pengujian memanggil jest.mock('./ModuleA') , yang memiliki tiruan di __mocks__/ModuleA.js . Tetapi ModuleA tidak sedang diuji, ModuleB - yang membutuhkan ModuleA - adalah yang sedang diuji. Tanpa solusi Anda, ModuleB akan mendapatkan implementasi ModuleA yang sebenarnya, bukan tiruannya.

Ini sepertinya perilaku yang sangat aneh dari lelucon. Saya berharap bahwa ketika saya memanggil jest.mock pada sebuah modul, modul apa pun yang sedang diuji yang memiliki ketergantungan pada modul yang diejek akan menggunakan tiruannya. Apakah ini tampak aneh karena tidak bekerja seperti itu, atau apakah saya melakukan ini sepenuhnya salah?

@SimenB Dalam contoh Anda, Anda memerlukan modul

@SimenB mengerjakan solusi Anda yang lebih sederhana untuk saya. Terima kasih! Berharap bisa menemukannya lebih awal sebelum saya menghabiskan waktu dengan berbagai cara

Dalam kasus saya, saya mengejek dan mengimpor jalur yang salah ke modul yang ingin saya rintis. Saya memiliki casing yang berbeda di jalur file sehingga editor saya pikir itu baik-baik saja tetapi gagal.

NS

const { stubMethod } = require("./path/to/File");
jest.mock("./path/to/File");

Diubah menjadi (ubah casing dari File menjadi file ):

const { stubMethod } = require("./path/to/file");
jest.mock("./path/to/file");

Semoga ini bisa membantu orang lain.

Jasmine spyOn() tidak memiliki masalah tes _inside_ seperti itu. Jest seharusnya menggunakan melati secara default? Mengapa tidak bekerja di dalam tes?

Contoh melati:

spyOn(require('moduleB'), 'functionA').and.callFake(() => true);

Apa yang saya tidak begitu mengerti ketika datang ke modul mengejek adalah bahwa itu selalu digambarkan seolah-olah Anda ingin menggunakan modul terutama dalam fungsi-tes Anda. Misalnya jika Anda melihat kode contoh untuk fungsi doMock di dokumen:

test('moduleName 2', () => {
  jest.doMock('../moduleName', () => {
    return {
      __esModule: true,
      default: 'default2',
      foo: 'foo2',
    };
  });
  return import('../moduleName').then(moduleName => {
    expect(moduleName.default).toEqual('default2');
    expect(moduleName.foo).toEqual('foo2');
  });
});

Dalam contoh ini, Anda memiliki akses ke versi baru dari "moduleName" di dalam fungsi pengujian saja. Bagi saya, jauh lebih penting bahwa kode "non-tes" saya juga memiliki akses ke versi modul yang diolok-olok. Misalnya Kelas yang saya gunakan di dalam pengujian saya, yang telah mengimpor "moduleName" akan tetap menggunakan versi asli, bukan versi tiruan.

Tampaknya terkait: https://github.com/facebook/jest/issues/3236

Tip - jika Anda memiliki modul yang mengekspor nilai primitif, misalnya:

```auth.js
ekspor const isUserAdmin = getSetting('admin');

And you want to use a mock value instead, in the test, then a simple require and assignment seems to do the trick:

```deleteUser.js
const auth = require('../auth');

describe('deleteUser', () => {
  it('can delete if admin', () => {
    auth.isUserAdmin = true;

    // call method that depends on isUserAdmin value
    // and assert on the result
  });
});

Jadi pada dasarnya, jika Anda ingin mengejek objek yang digunakan secara tidak langsung oleh kode yang Anda uji, fungsi jest.doMock() tidak akan berfungsi:

import myModuleToTest from './myModuleTotest'

describe('Given my module', () => {
  it('property1 will work as expect', () => {
    // Testing parts of the module that don't need to be mocked
  })

  it('property2 will work as expected', () => {
    jest.doMock('./myOtherModule', () => {
      return {
        __esModule: true,
        default: 'default2',
        foo: 'foo2',
      };
    });

    import('./myOtherModule').then(myOtherModule => {
      // I'm not interested on the mocked module myOtherModule but on the module that makes use of it
      myModuleToTest.doSomethingToSomeProperty(); // At this point myOtherModule's original module and not its mocked version will be used by myModuleToTest
      expect(myModuleToTest.someProperty).toBe('thisWillFail'); // The test won't pass because the mocked version wasn't used
    });
  });
});

Pada Jest 26 tidak ada cara untuk mengejek lebih dari sekali modul yang mengekspor Object yang digunakan secara tidak langsung (maksud saya mengejek sesuatu selain Function karena tidak ada mockFn.mockImplementation(fn) untuk mengejek Objects ). Apakah ini benar atau saya melewatkan sesuatu? Satu-satunya solusi kemudian adalah memiliki lebih dari satu file uji untuk menguji modul yang sama.

Anda harus mengimpor myModuleToTest setelah tiruan Anda karena jika itu mengimpor
sebelum mock tidak masuk akal. Jadi, jangan gunakan impor .... di atas atau
di dalam panggilan balik karena tetap diangkat.

Pada Selasa, 7 Juli 2020, 22:24 Antonio Redondo [email protected]
menulis:

Jadi pada dasarnya, jika Anda ingin mengejek objek yang digunakan secara tidak langsung oleh
kode yang Anda uji fungsi jest.doMock() tidak akan berfungsi:

impor myModuleToTest dari './myModuleTotest'
itu('akan bekerja', () => {
jest.doMock('./myOtherModule', () => {
kembali {
__esModule: benar,
default: 'default2',
foo: 'foo2',
};
});

return import('../myOtherModule').then(myOtherModule => {
// Saya tidak tertarik pada modul tiruan myOtherModule tetapi pada modul yang menggunakannya
myModuleToTest.doSomethingToSomeProperty(); // Pada titik ini modul asli myOtherModule dan bukan versi tiruannya akan digunakan oleh myModuleToTest
harapkan(myModuleToTest.someProperty).toBe('thisWillFail'); // Tes tidak akan lulus karena versi tiruan tidak digunakan
});});

Pada Jest 26 tidak ada cara untuk mengejek modul yang mengekspor Objek (I
berarti sesuatu selain Fungsi) yang digunakan secara tidak langsung. Apakah ini
benar atau saya melewatkan sesuatu? Satu-satunya solusi kemudian adalah memiliki lebih banyak
dari satu file tes untuk menguji modul yang sama.


Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung, lihat di GitHub
https://github.com/facebook/jest/issues/2582#issuecomment-655110424 , atau
berhenti berlangganan
https://github.com/notifications/unsubscribe-auth/AAJR3UW6HARW44ZLKAUB7PLR2N77NANCNFSM4C4I7QSQ
.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat