Menguji kode JavaScript dengan Jest untuk boneka. Bagian 1

Halo, Habr! Panduan ini adalah bagian pertama dari serangkaian artikel yang direncanakan tentang kerangka pengujian hebat seperti Jest. Materi akan berguna untuk pemula dan mereka yang baru saja berkenalan dengan pengujian, dan ingin mempelajari kerangka kerja ini. Pada bagian pertama kita akan membahas: bagaimana memulai dengan lelucon, bagaimana menulis tes sederhana, dan metode apa yang ada untuk membandingkan nilai yang akan diperiksa dengan yang diharapkan. Siapa yang peduli - selamat datang di kat!

Apa itu Jest?


Seperti yang ditunjukkan pada halaman beranda proyek:
Jest adalah lingkungan pengujian JavaScript yang luar biasa dengan fokus pada kesederhanaan.
Dan memang, Jest sangat sederhana. Tidak memerlukan pengaturan tambahan, mudah dimengerti dan digunakan, dan juga memiliki dokumentasi yang cukup bagus. Bagus untuk proyek yang menggunakan Node, React, Angular, Vue, Babel, TypeScript dan banyak lagi.
Ini juga open source dan didukung oleh Facebook.

Instalasi


Untuk menginstal Jest di proyek Anda, lakukan:

npm install --save-dev jest

Jika Anda menggunakan benang:

yarn add --dev jest

Setelah instalasi, Anda dapat memperbarui bagian skrip dari package.json Anda:

β€œscripts” : {
     β€œtest”: β€œjest”
}

Dengan panggilan sederhana ini, kita sudah dapat menjalankan tes kami (pada kenyataannya, bercanda akan membutuhkan setidaknya satu tes untuk ada).

Anda juga dapat menginstal secara global (tetapi saya tidak akan merekomendasikan melakukan ini, karena bagi saya instalasi global modul adalah praktik buruk):

npm install jest --global

Dan sesuai untuk benang:

yarn global add jest

Setelah itu, Anda dapat menggunakan lelucon langsung dari baris perintah.

Dengan memanggil perintah jest --init di root proyek, setelah menjawab beberapa pertanyaan, Anda akan mendapatkan file pengaturan jest.config.js. Atau Anda dapat menambahkan konfigurasi langsung ke package.json Anda. Untuk melakukan ini, tambahkan kunci "lelucon" ke root json dan pada objek yang sesuai Anda dapat menambahkan pengaturan yang Anda butuhkan. Kami akan menganalisis opsi sendiri nanti. Ini tidak perlu pada tahap ini, karena bercanda dapat digunakan segera, tanpa konfigurasi tambahan.

Tes pertama


Mari kita buat file first.test.js dan tulis tes pertama kami:

//first.test.js
test('My first test', () => {
    expect(Math.max(1, 5, 10)).toBe(10);
});

Dan jalankan pengujian kami menggunakan npm run test atau langsung dengan perintah jest (jika dipasang secara global). Setelah diluncurkan, kita akan melihat laporan tentang lulus tes.

 <b>PASS</b>  ./first.test.js
  βœ“ My first test (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.618 s, estimated 1 s

Mari kita selesaikan tes kita dan menjalankan lelucon lagi:

//first.test.js
test('My first test', () => {
    expect(Math.max(1, 5, 10)).toBe(5);
});

Seperti yang bisa kita lihat, sekarang ujian kita tidak lulus ujian. Jest menampilkan informasi terperinci tentang di mana masalah terjadi, apa hasil yang diharapkan, dan apa yang kami dapatkan.

Sekarang mari kita menganalisis kode tes itu sendiri. Fungsi tesdigunakan untuk membuat tes baru. Dibutuhkan tiga argumen (dalam contoh kami menggunakan panggilan dengan dua argumen). Yang pertama adalah baris dengan nama tes, leluconnya akan ditampilkan dalam laporan. Yang kedua adalah fungsi yang berisi logika pengujian kami. Anda juga dapat menggunakan argumen ke-3 - batas waktu. Ini opsional, dan nilai standarnya adalah 5 detik. Sudah diatur dalam milidetik. Parameter ini diperlukan ketika kita bekerja dengan kode asinkron dan mengembalikan janji dari fungsi pengujian. Ini menunjukkan berapa lama lelucon harus menunggu janji untuk diselesaikan. Setelah waktu ini, jika janji itu tidak diizinkan - bercanda akan menganggap tes gagal. Informasi lebih lanjut tentang bekerja dengan panggilan asinkron akan di bagian berikut. Atau, Anda dapat menggunakannya () alih-alih tes ().. Tidak ada perbedaan antara panggilan tersebut. it () hanyalah alias pada fungsi test () .

Di dalam fungsi tes, pertama-tama kita memanggil harapkan () . Baginya kita memberikan nilai yang ingin kita periksa. Dalam kasus kami, ini adalah hasil dari memanggil Math.max (1, 5, 10) . ekspektasi () mengembalikan objek pembungkus yang memiliki sejumlah metode untuk membandingkan nilai yang dihasilkan dengan yang diharapkan. Salah satu metode yang kami gunakan adalah toBe .

Mari kita lihat inti dari metode ini:

  • toBe() β€” , , . Object.is(). === 0 -0, NaN c NaN.
  • toEqual() β€” , . . . .

    test('toEqual with objects', () => {
        expect({ foo: 'foo', subObject: { baz: 'baz' } })
            .toEqual({ foo: 'foo', subObject: { baz: 'baz' } });  // 
        expect({ foo: 'foo', subObject: { num: 0 } })
            .toEqual({ foo: 'foo', subObject: { baz: 'baz' } });  //    .
    });
    
    test('toEqual with arrays', () => {
        expect([11, 19, 5]).toEqual([11, 19, 5]); // 
        expect([11, 19, 5]).toEqual([11, 19]); // 
    });
    

  • toContain() β€” . ===.

    const arr = ['apple', 'orange', 'banana'];
    expect(arr).toContain('banana');
    expect(new Set(arr)).toContain('banana');
    expect('apple, orange, banana').toContain('banana');
    

  • toContainEqual() β€” .

    expect([{a: 1}, {b: 2}]).toContainEqual({a: 1});
    

  • toHaveLength() β€” length .

    expect([1, 2, 3, 4]).toHaveLength(4);
    expect('foo').toHaveLength(3);
    expect({ length: 1 }).toHaveLength(1);
    

  • toBeNull() β€” null.
  • toBeUndefined() β€” undefined.
  • toBeDefined() β€” toBeUndefined. !== undefined.
  • toBeTruthy() β€” true. false, null, undefined, 0, NaN .
  • toBeFalsy() β€” toBeTruthy(). false.
  • toBeGreaterThan() toBeGreaterThanOrEqual() β€” , >, >=.
  • toBeLessThan() toBeLessThanOrEqual() β€” toBeGreaterThan() toBeGreaterThanOrEqual()
  • toBeCloseTo() β€” , , . .

    const num = 0.1 + 0.2; // 0.30000000000000004
    expect(num).toBeCloseTo(0.3);
    expect(Math.PI).toBeCloseTo(3.14, 2);
    

  • toMatch() β€” .

    expect('Banana').toMatch(/Ba/);
    

  • toThrow () - digunakan saat diperlukan untuk memeriksa pengecualian. Anda dapat memeriksa fakta kesalahan itu sendiri dan memeriksa untuk melempar pengecualian dari kelas tertentu, baik dengan pesan kesalahan atau dengan korespondensi pesan dengan ekspresi reguler.

    function funcWithError() {
        throw new Error('some error');
    }   
    expect(funcWithError).toThrow();
    expect(funcWithError).toThrow(Error);
    expect(funcWithError).toThrow('some error');
    expect(funcWithError).toThrow(/some/);
    

  • tidak - properti ini memungkinkan Anda untuk memeriksa Ketimpangan. Ini menyediakan objek yang memiliki semua metode yang tercantum di atas, tetapi mereka akan bekerja sebaliknya.

    expect(true).not.toBe(false);
    expect({ foo: 'bar' }).not.toEqual({});
    
    function funcWithoutError() {}
    expect(funcWithoutError).not.toThrow();
    

Mari kita menulis beberapa tes sederhana. Pertama, buat modul sederhana yang akan berisi beberapa metode untuk bekerja dengan lingkaran.

// src/circle.js
const area = (radius) => Math.PI * radius ** 2;
const circumference = (radius) => 2 * Math.PI * radius;
module.exports = { area, circumference };

Selanjutnya, tambahkan tes:

// tests/circle.test.js
const circle = require('../src/circle');

test('Circle area', () => {
    expect(circle.area(5)).toBeCloseTo(78.54);
    expect(circle.area()).toBeNaN();
});

test('Circumference', () => {
    expect(circle.circumference(11)).toBeCloseTo(69.1, 1);
    expect(circle.circumference()).toBeNaN();
});

Dalam tes ini, kami memeriksa hasil 2 metode - area dan keliling . Menggunakan metode toBeCloseTo, kami memeriksa hasil yang diharapkan. Dalam kasus pertama, kami memeriksa atau area terhitung lingkaran dengan jari-jari 5 kira-kira sama dengan 78,54, sedangkan perbedaan dengan nilai yang diperoleh (itu akan menjadi 78,53981633974483) tidak besar dan tes akan dihitung. Di yang kedua, kami mengindikasikan bahwa kami tertarik untuk memeriksa dalam 1 desimal. Kami juga memanggil metode kami tanpa argumen dan memeriksa hasilnya menggunakan toBeNaN . Karena hasil eksekusi mereka adalah NaN, maka tes akan berhasil dilewati.

Mari kita ambil contoh lain. Mari kita membuat fungsi yang akan memfilter berbagai produk berdasarkan harga:

// src/productFilter.js
const byPriceRange = (products, min, max) =>
         products.filter(item => item.price >= min && item.price <= max);
module.exports = { byPriceRange };

Dan tambahkan tes:

// tests/product.test.js
const productFilter = require('../src/producFilter');

const products = [
    { name: 'onion', price: 12 },
    { name: 'tomato', price: 26 },
    { name: 'banana', price: 29 },
    { name: 'orange', price: 38 }
];

test('Test product filter by range', () => {
    const FROM = 15;
    const TO = 30;
    const filteredProducts = productFilter.byPriceRange(products, FROM, TO);

    expect(filteredProducts).toHaveLength(2);
    expect(filteredProducts).toContainEqual({ name: 'tomato', price: 26 });
    expect(filteredProducts).toEqual([{ name: 'tomato', price: 26 }, { name: 'banana', price: 29 }]);
    expect(filteredProducts[0].price).toBeGreaterThanOrEqual(FROM);
    expect(filteredProducts[1].price).toBeLessThanOrEqual(TO);
    expect(filteredProducts).not.toContainEqual({ name: 'orange', price: 38 });
});

Dalam tes ini, kita akan memeriksa hasil fungsi byRangePrice . Pertama, kami memeriksa korespondensi panjang array yang dihasilkan dengan yang diharapkan - 2. Pemeriksaan berikutnya mengharuskan elemen berisi elemen - {nama: 'tomat', harga: 26}. Objek dalam array dan objek yang diteruskan ke ContainEqual adalah dua objek yang berbeda, bukan referensi yang sama. Tetapi toContainEqual akan membandingkan setiap properti. Karena kedua objek identik, verifikasi akan berhasil. Selanjutnya, kita menggunakan toEqual untuk memeriksa struktur seluruh array dan elemen-elemennya. Metode toBeGreaterThanOrEqual dan toBeLessThanOrEqual akan membantu kami memeriksa harga elemen array pertama dan kedua. Dan akhirnya, menelepon not. ToContainEqualakan memeriksa apakah elemen tersebut terdapat dalam array - {name: 'orange', price: 38}, yang, dengan ketentuan, tidak boleh ada di sana.

Dalam contoh ini, kami menulis beberapa tes sederhana menggunakan fungsi verifikasi yang dijelaskan di atas. Pada bagian berikut, kita akan membahas pekerjaan dengan kode asinkron, fungsi lelucon yang tidak tercakup dalam bagian tutorial ini, kita akan berbicara tentang konfigurasinya, dan banyak lagi.

All Articles