Rumah  >  Artikel  >  hujung hadapan web  >  Pengenalan kepada Jest: Ujian Unit, Mengejek dan Kod Asynchronous

Pengenalan kepada Jest: Ujian Unit, Mengejek dan Kod Asynchronous

Linda Hamilton
Linda Hamiltonasal
2024-11-01 00:23:28597semak imbas

Introduction to Jest: Unit Testing, Mocking, and Asynchronous Code

Pengenalan kepada Jest

Jest ialah perpustakaan untuk menguji kod JavaScript.

Ia adalah projek sumber terbuka yang diselenggara oleh Facebook, dan ia amat sesuai untuk ujian kod React, walaupun tidak terhad kepada itu: ia boleh menguji mana-mana kod JavaScript. Kekuatannya ialah:

  • cepat
  • ia boleh melakukan ujian syot kilat
  • ia mempunyai pendapat, dan menyediakan segala-galanya di luar kotak tanpa memerlukan anda membuat pilihan
export default function sum(a, n) {
  return a + b;
}

divide.test.js

import sum from './sum';

// Describe the test and wrap it in a function.
it('adds 1 + 2 to equal 3', () => {
  const result = sum(1, 2);

  // Jest uses matchers, like pretty much any other JavaScript testing framework.
  // They're designed to be easy to get at a glance;
  // here, you're expecting `result` to be 3.
  expect(result).toBe(3);
});

Matchers

Penjodoh ialah kaedah yang membolehkan anda menguji nilai.

  • toBe membandingkan kesaksamaan yang ketat, menggunakan ===
  • toEqual membandingkan nilai dua pembolehubah. Jika ia objek atau tatasusunan, ia menyemak kesamaan semua sifat atau elemen
  • toBeNull adalah benar apabila menghantar nilai null
  • toBeDefined adalah benar apabila menghantar nilai yang ditentukan (bertentangan dengan yang di atas)
  • toBeUndefined adalah benar apabila menghantar nilai yang tidak ditentukan
  • toBeCloseTo digunakan untuk membandingkan nilai terapung, mengelakkan ralat pembundaran
  • toBeTruthy true jika nilai itu dianggap benar (seperti if does)
  • toBeFalsy true jika nilai dianggap palsu (seperti if does)
  • toBeGreaterThan true jika hasil expect() lebih tinggi daripada hujah
  • toBeGreaterThanOrEqual true jika hasil expect() adalah sama dengan hujah, atau lebih tinggi daripada hujah
  • toBeLessThan true jika hasil expect() adalah lebih rendah daripada hujah
  • toBeLessThanOrEqual true jika hasil expect() adalah sama dengan hujah, atau lebih rendah daripada hujah
  • toMatch digunakan untuk membandingkan rentetan dengan padanan corak ungkapan biasa
  • toContain digunakan dalam tatasusunan, benar jika tatasusunan yang dijangkakan mengandungi hujah dalam set elemennya
  • toHaveLength(number): menyemak panjang tatasusunan
  • toHaveProperty(key, value): menyemak sama ada objek mempunyai harta dan secara pilihan menyemak nilainya
  • toThrow menyemak sama ada fungsi yang anda lalui membuang pengecualian (secara umum) atau pengecualian khusus
  • toBeInstanceOf(): menyemak sama ada objek ialah contoh kelas

Kebergantungan

Pergantungan ialah sekeping kod yang bergantung pada aplikasi anda. Ia boleh menjadi fungsi/Objek dalam projek kami atau pergantungan pihak ketiga (ex axios)

Sekeping kod menjadi kebergantungan sebenar apabila aplikasi anda sendiri tidak dapat berfungsi tanpanya.

Sebagai contoh, jika anda melaksanakan ciri dalam aplikasi anda untuk menghantar e-mel atau membuat permintaan api atau membina objek konfigurasi dll

Terdapat dua cara yang boleh kami tambahkan kebergantungan dalam kod kami dalam projek js:

Import

export default function sum(a, n) {
  return a + b;
}

Suntikan Ketergantungan

Sekadar istilah mewah pada konsep yang mudah.

Jika fungsi anda memerlukan beberapa kefungsian daripada kebergantungan luaran, hanya masukkannya sebagai hujah.

import sum from './sum';

// Describe the test and wrap it in a function.
it('adds 1 + 2 to equal 3', () => {
  const result = sum(1, 2);

  // Jest uses matchers, like pretty much any other JavaScript testing framework.
  // They're designed to be easy to get at a glance;
  // here, you're expecting `result` to be 3.
  expect(result).toBe(3);
});

Pengujian Unit

Ujian unit ditulis dan dijalankan oleh pembangun perisian untuk memastikan bahagian aplikasi (dikenali sebagai "unit") memenuhi reka bentuknya dan berfungsi seperti yang dimaksudkan.

Kami ingin menguji kod kami secara berasingan, kami tidak mengambil berat tentang pelaksanaan sebenar sebarang kebergantungan.
Kami ingin mengesahkan

  • bahawa unit kod kami berfungsi seperti yang diharapkan
  • mengembalikan hasil yang diharapkan
  • memanggil mana-mana kolaborator(pergantungan) sebagaimana mestinya

Dan di situlah ejekan kebergantungan kita berlaku.

mengejek

Dalam ujian unit, olok-olok memberikan kami keupayaan untuk stub fungsi yang disediakan oleh kebergantungan dan bermaksud untuk memerhatikan cara kod kami berinteraksi dengan kebergantungan.

Olok-olok amat berguna apabila mahal atau tidak praktikal untuk memasukkan pergantungan terus ke dalam ujian kami, contohnya, dalam kes di mana kod anda membuat panggilan HTTP ke API atau berinteraksi dengan lapisan pangkalan data.

Adalah lebih baik untuk menolak respons untuk kebergantungan ini, sambil memastikan bahawa ia dipanggil mengikut keperluan. Di sinilah ejekan berguna.

Dengan menggunakan fungsi olok-olok, kita boleh mengetahui perkara berikut:

  • bilangan panggilan yang diterima.
  • Nilai Argumen yang digunakan pada setiap seruan.
  • Nilai “konteks” atau ini pada setiap seruan.
  • Cara fungsi keluar dan nilai apa yang dihasilkan.

Mengejek dalam Jest

Terdapat beberapa cara untuk mencipta fungsi olok-olok.

  • Kaedah jest.fn membolehkan kami mencipta fungsi olok-olok baharu secara langsung.
  • Jika anda mengejek kaedah objek, anda boleh menggunakan jest.spyOn.
  • Dan jika anda ingin mengejek keseluruhan modul, anda boleh menggunakan jest.mock.

Kaedah jest.fn adalah, dengan sendirinya, fungsi tertib lebih tinggi.

Ia adalah kaedah kilang yang mencipta fungsi olok-olok baharu yang tidak digunakan.

Fungsi dalam JavaScript adalah warga kelas pertama, ia boleh dihantar sebagai hujah.

Setiap fungsi olok-olok mempunyai beberapa ciri istimewa. Harta olok-olok adalah asas. Sifat ini ialah objek yang mempunyai semua maklumat keadaan olok-olok tentang cara fungsi itu digunakan. Objek ini mengandungi tiga sifat tatasusunan:

  • Panggilan [hujah setiap panggilan]
  • Instance [nilai 'ini' pada setiap panggilan]
  • Keputusan [nilai yang fungsi keluar], harta hasil mempunyai jenis (return atau throw) dan nilai
    • Fungsi ini secara eksplisit mengembalikan nilai.
    • Fungsi berjalan hingga selesai tanpa penyataan pemulangan (yang bersamaan dengan pemulangan tidak ditentukan
    • Fungsi melemparkan ralat.
export default function sum(a, n) {
  return a + b;
}
  • https://codesandbox.io/s/implementing-mock-functions-tkc8b

Mock Basic

import sum from './sum';

// Describe the test and wrap it in a function.
it('adds 1 + 2 to equal 3', () => {
  const result = sum(1, 2);

  // Jest uses matchers, like pretty much any other JavaScript testing framework.
  // They're designed to be easy to get at a glance;
  // here, you're expecting `result` to be 3.
  expect(result).toBe(3);
});

Mengejek kebergantungan yang disuntik

import { name, draw, reportArea, reportPerimeter } from './modules/square.js';

Modul mengejek

Mengejek fungsi dengan jest.fn

// Constructor Injection

// DatabaseManager class takes a database connector as a dependency
class DatabaseManager {
    constructor(databaseConnector) {
        // Dependency injection of the database connector
        this.databaseConnector = databaseConnector;
    }

    updateRow(rowId, data) {
        // Use the injected database connector to perform the update
        this.databaseConnector.update(rowId, data);
    }
}

// parameter injection, takes a database connector instance in as an argument; easy to test!
function updateRow(rowId, data, databaseConnector) {
    databaseConnector.update(rowId, data);
}

Jenis ejekan ini kurang biasa atas beberapa sebab:

  • jest.mock melakukan ini secara automatik untuk semua fungsi dalam modul
  • jest.spyOn melakukan perkara yang sama tetapi membenarkan memulihkan fungsi asal

Olok-olok modul dengan jest.mock

Pendekatan yang lebih biasa ialah menggunakan jest.mock untuk menetapkan semua eksport modul secara automatik kepada Fungsi Mock.

// 1. The mock function factory
function fn(impl = () => {}) {
  // 2. The mock function
  const mockFn = function(...args) {
    // 4. Store the arguments used
    mockFn.mock.calls.push(args);
    mockFn.mock.instances.push(this);
    try {
      const value = impl.apply(this, args); // call impl, passing the right this
      mockFn.mock.results.push({ type: 'return', value });
      return value; // return the value
    } catch (value) {
      mockFn.mock.results.push({ type: 'throw', value });
      throw value; // re-throw the error
    }
  }
  // 3. Mock state
  mockFn.mock = { calls: [], instances: [], results: [] };
  return mockFn;
}

Mengintip atau mengejek fungsi dengan jest.spyOn

Kadangkala anda hanya mahu melihat kaedah dipanggil, tetapi mengekalkan pelaksanaan asal. Pada masa lain anda mungkin ingin mengejek pelaksanaan, tetapi pulihkan yang asal kemudian dalam suite.

test("returns undefined by default", () => {
  const mock = jest.fn();

  let result = mock("foo");

  expect(result).toBeUndefined();
  expect(mock).toHaveBeenCalled();
  expect(mock).toHaveBeenCalledTimes(1);
  expect(mock).toHaveBeenCalledWith("foo");
});

Pulihkan pelaksanaan asal

const doAdd = (a, b, callback) => {
  callback(a + b);
};

test("calls callback with arguments added", () => {
  const mockCallback = jest.fn();
  doAdd(1, 2, mockCallback);
  expect(mockCallback).toHaveBeenCalledWith(3);
});

Javascript dan Gelung Acara

JavaScript adalah satu benang: hanya satu tugasan boleh dijalankan pada satu masa. Biasanya itu bukan masalah besar, tetapi sekarang bayangkan anda menjalankan tugas yang mengambil masa 30 saat.. Ya.. Semasa tugasan itu kami menunggu selama 30 saat sebelum perkara lain boleh berlaku (JavaScript berjalan pada utas utama penyemak imbas secara lalai, jadi keseluruhan UI tersekat).
Sekarang tahun 2020, tiada siapa yang mahukan tapak web yang lambat dan tidak responsif.

Mujurlah, penyemak imbas memberikan kami beberapa ciri yang tidak disediakan oleh enjin JavaScript itu sendiri: API Web. Ini termasuk DOM API, setTimeout, permintaan HTTP dan sebagainya. Ini boleh membantu kami mencipta beberapa tak segerak, gelagat tidak menyekat

export default function sum(a, n) {
  return a + b;
}
  • Timbunan Panggilan - Apabila kita menggunakan fungsi, ia akan ditambahkan pada sesuatu yang dipanggil timbunan panggilan.
  • WebAPI - setTimeout disediakan oleh WebAPI, mengambil fungsi panggil balik dan menyediakan pemasa tanpa menyekat utas utama
  • Baris Gilir - apabila pemasa selesai, panggilan balik akan ditambahkan ke dalam Baris Gilir
  • Gelung Peristiwa - menyemak sama ada tindanan panggilan kosong, menyemak sama ada terdapat sebarang panggilan balik untuk dilaksanakan dalam Baris Gilir, dan bergerak ke tindanan panggilan untuk dilaksanakan
import sum from './sum';

// Describe the test and wrap it in a function.
it('adds 1 + 2 to equal 3', () => {
  const result = sum(1, 2);

  // Jest uses matchers, like pretty much any other JavaScript testing framework.
  // They're designed to be easy to get at a glance;
  // here, you're expecting `result` to be 3.
  expect(result).toBe(3);
});

Menguji kod tak segerak dengan Jest

Jest biasanya mengharapkan untuk melaksanakan fungsi ujian segera.

Jika kami melakukan operasi tak segerak, tetapi kami tidak memberitahu Jest bahawa ia sepatutnya menunggu sehingga ujian tamat, ia akan memberikan positif palsu.

import { name, draw, reportArea, reportPerimeter } from './modules/square.js';

Corak Tak Segerak
Terdapat beberapa corak untuk mengendalikan operasi async dalam JavaScript; yang paling banyak digunakan ialah:

  • Panggil balik
  • Janji & Async/Menunggu

Menguji Panggilan Balik

Anda tidak boleh mempunyai ujian dalam panggilan balik, kerana Jest tidak akan melaksanakannya - pelaksanaan fail ujian tamat sebelum panggilan balik dipanggil. Untuk membetulkannya, hantar parameter kepada fungsi ujian, yang anda boleh panggil selesai dengan mudah. Jest akan menunggu sehingga anda memanggil done() sebelum menamatkan ujian itu:

// Constructor Injection

// DatabaseManager class takes a database connector as a dependency
class DatabaseManager {
    constructor(databaseConnector) {
        // Dependency injection of the database connector
        this.databaseConnector = databaseConnector;
    }

    updateRow(rowId, data) {
        // Use the injected database connector to perform the update
        this.databaseConnector.update(rowId, data);
    }
}

// parameter injection, takes a database connector instance in as an argument; easy to test!
function updateRow(rowId, data, databaseConnector) {
    databaseConnector.update(rowId, data);
}

Janji

Dengan fungsi yang mengembalikan janji, kami mengembalikan janji daripada ujian:

// 1. The mock function factory
function fn(impl = () => {}) {
  // 2. The mock function
  const mockFn = function(...args) {
    // 4. Store the arguments used
    mockFn.mock.calls.push(args);
    mockFn.mock.instances.push(this);
    try {
      const value = impl.apply(this, args); // call impl, passing the right this
      mockFn.mock.results.push({ type: 'return', value });
      return value; // return the value
    } catch (value) {
      mockFn.mock.results.push({ type: 'throw', value });
      throw value; // re-throw the error
    }
  }
  // 3. Mock state
  mockFn.mock = { calls: [], instances: [], results: [] };
  return mockFn;
}

Async/menunggu

Untuk menguji fungsi yang mengembalikan janji, kami juga boleh menggunakan async/menunggu, yang menjadikan sintaks sangat mudah dan mudah:

test("returns undefined by default", () => {
  const mock = jest.fn();

  let result = mock("foo");

  expect(result).toBeUndefined();
  expect(mock).toHaveBeenCalled();
  expect(mock).toHaveBeenCalledTimes(1);
  expect(mock).toHaveBeenCalledWith("foo");
});

Petua

  • Kita perlu mempunyai pemahaman yang baik tentang fungsi kita dan perkara yang akan kita uji
  • Fikirkan tentang kelakuan kod yang kami uji
  • Tetapkan pentas:
    • Ejek/Intip sebarang kebergantungan
    • Adakah kod kami berinteraksi dengan objek global? kita boleh mengejek/mengintip mereka juga
    • Adakah ujian kami berinteraksi dengan DOM? kita boleh membina beberapa elemen palsu untuk digunakan
    • Struktur ujian anda
    • Memandangkan ...
    • Apabila saya memanggil ....
    • Kemudian ... saya jangkakan.....
const doAdd = (a, b, callback) => {
  callback(a + b);
};

test("calls callback with arguments added", () => {
  const mockCallback = jest.fn();
  doAdd(1, 2, mockCallback);
  expect(mockCallback).toHaveBeenCalledWith(3);
});

Pautan

  • https://medium.com/@rickhanlonii/understanding-jest-mocks-f0046c68e53c
  • https://jestjs.io/docs/en/mock-functions
  • https://codesandbox.io/s/implementing-mock-functions-tkc8b
  • https://github.com/BulbEnergy/jest-mock-examples
  • https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
  • https://jestjs.io/docs/ms/asynchronous
  • https://www.pluralsight.com/guides/test-asynchronous-code-jest

Atas ialah kandungan terperinci Pengenalan kepada Jest: Ujian Unit, Mengejek dan Kod Asynchronous. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn