Knex: Cara menulis pengujian unit untuk metode yang menggunakan Knex.

Dibuat pada 21 Mei 2017  ·  28Komentar  ·  Sumber: knex/knex

(Awalnya diposting di # 1659, pindah ke sini untuk diskusi lebih lanjut.)

Saya agak tidak tahu apa-apa tentang yang satu ini - dokumen knex mencakup barebone transaksi, tetapi ketika saya google "menggunakan knex.js untuk pengujian unit" dan "ava.js + knex" dan "ava.js + database" , Saya tidak dapat menemukan sesuatu yang sangat instruktif untuk menunjukkan kepada saya cara yang baik, jadi saya kembali ke pengalaman Ruby saya di mana membungkus pengujian unit dalam transaksi adalah teknik umum untuk mengatur ulang DB setelah setiap pengujian.

@odigity Saya tidak akan menyarankan melakukan itu karena pengujian Anda akan berakhir hanya menggunakan satu koneksi, bukan kumpulan koneksi dan itu tidak akan mewakili penggunaan dunia nyata dari aplikasi Anda.

Itu benar-benar terjadi pada saya, tetapi saya bersedia menerima bahwa jika memungkinkan saya menggunakan metode sederhana sekali tulis untuk menerapkan pembersihan DB pasca-tes. (Saya memang mengatur pool min / max saya ke 1 untuk memastikan.) Jika ada cara untuk mencapai ini sambil mendukung koneksi bersamaan, saya akan sepenuhnya menerimanya.

Juga sangat tidak mungkin untuk diterapkan kecuali jika aplikasi yang Anda uji menjalankan kuerinya dalam transaksi yang sama yang dimulai di dalam kode pengujian (Anda perlu memulai transaksi dalam pengujian kemudian memulai aplikasi Anda dan meneruskan transaksi yang dibuat ke aplikasi sehingga membuat semua kueri ke transaksi yang sama dan transaksi bertingkat mungkin berperilaku kelaparan ...).

Cara saya berharap / mengharapkannya berhasil adalah:

1) Dalam setiap pengujian unit, saya membuat transaksi yang menghasilkan trx .

2) Saya kemudian memerlukan modul yang ingin saya uji dan meneruskan objek trx ke konstruktor modul sehingga akan digunakan oleh modul, sehingga menghasilkan semua kueri yang terjadi di dalam transaksi.

3) Setelah metode modul kembali (atau melempar kesalahan), saya menjalankan pernyataan saya pada status hasil DB, kemudian memanggil trx.rollback() untuk membatalkan semuanya dari awal untuk mempersiapkan pengujian berikutnya.

Jadi, itulah yang saya coba capai dan bagaimana saya awalnya ingin mencapainya. Saya ingin mempelajari lebih lanjut tentang:

1) Mengapa saya salah paham tentang cara kerja Knex.js dan harus digunakan.

2) Praktik terbaik untuk menulis pengujian unit atom untuk kode yang menyentuh database.

question

Komentar yang paling membantu

Tidak - tidak mendapat apa-apa. Ringkasan dalam urutan kronologis sumber:

21-04-2016 https://medium.com/@jomaora/knex -bookshelf-mengolok-olok-dan-unit-tes-cca627565d3

Strategi: Gunakan mock-knex . Saya tidak ingin mengejek DB - Saya ingin menguji metode saya terhadap MySQL DB yang sebenarnya untuk memastikan perilaku yang benar - tetapi saya melihat mock-knex ... itu mungkin saja perpustakaan yang dirancang paling buruk Yang pernah saya temui. :(

2016-04-28 http://mherman.org/blog/2016/04/28/test-driven-development-with-node/

Strategi: Rollback / remigrate / reseed DB setelah setiap tes. Tampaknya itu merupakan overhead yang besar untuk setiap pengujian, dan akan berjalan sangat lambat. Konkurensi dapat dicapai dengan menghasilkan UUID untuk setiap nama DB pengujian, tetapi itu sepertinya solusi yang buruk dibandingkan dengan keanggunan transaksi ...

2015-09-23 http://stackoverflow.com/a/32749601/210867

Strategi: Gunakan sqlite untuk pengujian, buat / hancurkan DB untuk setiap pengujian. Saya telah membahas kedua alasan saya tidak menyukai pendekatan di atas.

Jadi ... masih mencari saran, dan panduan tambahan tentang cara kerja transaksi Knex, serta cara menerapkannya dengan benar ke kasus penggunaan saya.

Semua 28 komentar

Tampaknya saya melakukan pekerjaan googling yang buruk tadi malam, karena saya baru saja mencoba lagi dengan "cara menulis pengujian unit atom dengan knex.js", dan saya mendapatkan beberapa hasil yang menarik. Akan membacanya sekarang. Akan memposting lagi jika saya belajar sesuatu.

Tidak - tidak mendapat apa-apa. Ringkasan dalam urutan kronologis sumber:

21-04-2016 https://medium.com/@jomaora/knex -bookshelf-mengolok-olok-dan-unit-tes-cca627565d3

Strategi: Gunakan mock-knex . Saya tidak ingin mengejek DB - Saya ingin menguji metode saya terhadap MySQL DB yang sebenarnya untuk memastikan perilaku yang benar - tetapi saya melihat mock-knex ... itu mungkin saja perpustakaan yang dirancang paling buruk Yang pernah saya temui. :(

2016-04-28 http://mherman.org/blog/2016/04/28/test-driven-development-with-node/

Strategi: Rollback / remigrate / reseed DB setelah setiap tes. Tampaknya itu merupakan overhead yang besar untuk setiap pengujian, dan akan berjalan sangat lambat. Konkurensi dapat dicapai dengan menghasilkan UUID untuk setiap nama DB pengujian, tetapi itu sepertinya solusi yang buruk dibandingkan dengan keanggunan transaksi ...

2015-09-23 http://stackoverflow.com/a/32749601/210867

Strategi: Gunakan sqlite untuk pengujian, buat / hancurkan DB untuk setiap pengujian. Saya telah membahas kedua alasan saya tidak menyukai pendekatan di atas.

Jadi ... masih mencari saran, dan panduan tambahan tentang cara kerja transaksi Knex, serta cara menerapkannya dengan benar ke kasus penggunaan saya.

@odigity dengan baik menyimpulkan praktik pengujian yang buruk 👍

Kami melakukan pengujian "unit" kami seperti ini:

  1. Mulai sistem, inisialisasi DB, dan jalankan migrasi

  2. Sebelum setiap pengujian kami memotong semua tabel dan urutan (dengan paket knex-db-manager)

  3. Masukkan data yang diperlukan untuk kasus uji (kami menggunakan knex berbasis objection.js ORM untuk itu yang memungkinkan kami untuk memasukkan hierarki objek bersarang dengan perintah tunggal, ia tahu cara mengoptimalkan penyisipan sehingga tidak perlu melakukan penyisipan terpisah untuk setiap baris di tabel, tetapi biasanya hanya satu sisipan per tabel)

  4. jalankan 1 tes dan lanjutkan ke langkah 2

Dengan pengujian e2e, kami telah mengimplementasikan metode saveState / restoreState (dengan pg_restore / pg_dump), yang memungkinkan kami untuk memutar kembali ke status tertentu selama pengujian dijalankan, jadi kami tidak perlu memulai ulang pengujian setiap kali beberapa pengujian gagal setelah menjalankan 20 menit tes.

Itu mirip dengan apa yang saya mulai lakukan kemarin karena sederhana dan lurus ke depan dan saya perlu membuat kemajuan.

Sudahkah Anda mempertimbangkan strategi menggabungkan pengujian dalam transaksi dan memutar kembali setelahnya sebagai alternatif yang lebih cepat untuk memotong semua tabel? Itu sepertinya ideal bagi saya, jika saya bisa mengetahui implementasinya.

Saya kira jika Anda menjalankan db dan kode aplikasi dalam proses yang sama Anda dapat membuat transaksi dalam kode pengujian dan kemudian mendaftarkan transaksi itu untuk menjadi knex-instance Anda (contoh knex dan transaksi terlihat sedikit berbeda dalam beberapa kasus tetapi biasanya Anda dapat menggunakan transaksi Misalnya seperti contoh knex normal).

Kemudian Anda memulai kode aplikasi Anda, yang mengambil transaksi alih-alih instance knex gabungan normal dan mulai melakukan kueri melalui itu.

Hampir sama dengan yang Anda jelaskan di OP. Bagaimana Anda menggambarkannya terdengar layak.

Saya telah mempertimbangkan untuk menggunakan transaksi untuk menyetel ulang DB dalam pengujian beberapa tahun yang lalu, tetapi menolaknya karena saya ingin menghubungkan penggabungan untuk bekerja dalam pengujian dengan cara yang hampir sama seperti cara kerjanya di aplikasi + truncate / init cukup cepat bagi kami.

Apakah tidak ada cara untuk mencapai afinitas koneksi selama durasi transaksi sehingga semua kueri yang dijalankan dalam satu batch akan menggunakan koneksi yang sama, dan dengan demikian dapat digabungkan dalam satu transaksi?

Jenis strategi pemotongan berhasil, tetapi itu sangat kasar. Saat ini saya memiliki pengait test.after.always () di setiap file pengujian yang memotong tabel yang dipengaruhi oleh pengujian di file itu (biasanya satu tabel per file), tetapi saya dapat memikirkan kasus tepi yang akan kacau karenanya.

Misalnya, jika dua pengujian dari file pengujian berbeda yang menyentuh tabel yang sama dijalankan pada waktu yang sama, kait pemotongan satu file mungkin dimulai saat pengujian file kedua sedang berjalan, mengacaukan pengujian itu.

Terakhir, saya masih belum jelas tentang cara kerja transaksi di Knex. Jika saya membuat trx dengan knex.transaction() , apakah semua kueri yang dijalankan menggunakan trx secara otomatis menjadi bagian dari transaksi? Apakah saya harus melakukan / memutar balik secara manual? (Dengan asumsi tidak ada kesalahan yang dilempar.)

Apakah tidak ada cara untuk mencapai afinitas koneksi selama durasi transaksi sehingga semua kueri yang dijalankan dalam satu batch akan menggunakan koneksi yang sama, dan dengan demikian dapat digabungkan dalam satu transaksi?

Saya tidak mengerti ini

Jenis strategi pemotongan berhasil, tetapi itu sangat kasar. Saat ini saya memiliki pengait test.after.always () di setiap file pengujian yang memotong tabel yang dipengaruhi oleh pengujian di file itu (biasanya satu tabel per file), tetapi saya dapat memikirkan kasus tepi yang akan kacau karenanya.

Misalnya, jika dua pengujian dari file pengujian berbeda yang menyentuh tabel yang sama dijalankan pada waktu yang sama, kait pemotongan satu file mungkin dimulai saat pengujian file kedua sedang berjalan, mengacaukan pengujian itu.

Meskipun Anda menggunakan transaksi untuk menyetel ulang data pengujian, Anda tidak akan dapat menjalankan beberapa pengujian secara paralel dalam kasus umum. Urutan id akan berbeda dan transaksi mungkin menemui jalan buntu dll.

Terakhir, saya masih belum jelas tentang cara kerja transaksi di Knex. Jika saya membuat trx dengan knex.transaction (), apakah semua kueri yang dijalankan menggunakan trx secara otomatis menjadi bagian dari transaksi? Apakah saya harus melakukan / memutar balik secara manual? (Dengan asumsi tidak ada kesalahan yang dilempar.)

Yang ini ditemukan dari dokumentasi. Jika Anda tidak mengembalikan promise dari callback di knex.transaction(callback) Anda perlu melakukan / rollback secara manual. Jika callback mengembalikan promise, maka commit / rollback akan dipanggil secara otomatis. Dalam kasus Anda, Anda mungkin harus melakukan rollback secara manual.

Meskipun Anda menggunakan transaksi untuk menyetel ulang data pengujian, Anda tidak akan dapat menjalankan beberapa pengujian secara paralel dalam kasus umum. Urutan id akan berbeda dan transaksi mungkin menemui jalan buntu dll.

Saya membuat ID secara acak untuk setiap catatan yang saya masukkan. Tabrakan mungkin terjadi, tetapi tidak mungkin, dan jika terjadi sekali dalam suatu hari, itu hanya tes - bukan kode yang dihadapi pelanggan.

Untuk konkurensi, saya berasumsi semua kueri yang perlu dikelompokkan ke dalam satu transaksi juga harus menggunakan koneksi DB yang sama, yang dapat saya capai dengan menyetel ukuran kumpulan Knex saya ke 1. Saya kemudian perlu melakukan pengujian di file serial dengan pengubah .serial . Namun, saya masih memiliki konkurensi antara file pengujian (yang merupakan faktor paling signifikan untuk kinerja) karena Ava menjalankan setiap file pengujian dalam proses anak terpisah.

Saya kira saya harus mencobanya.

Saya berhasil!

https://gist.github.com/odigity/7f37077de74964051d45c4ca80ec3250

Saya menggunakan Ava untuk pengujian unit dalam proyek saya, tetapi untuk contoh ini, saya baru saja membuat skenario pengujian unit tiruan dengan kait sebelum / sesudah untuk mendemonstrasikan konsep tersebut.

Sebelum Hook

  • Karena memperoleh transaksi adalah tindakan asinkron, saya membuat Janji baru untuk kembali dari hook before dan menangkap metode resolve sehingga dapat dipanggil dalam callback transaction() .
  • Saya membuka transaksi. Dalam panggilan balik, saya ...

    • simpan pegangan tx di tempat yang dapat diakses oleh pengujian dan after hook

    • panggil metode simpanan resolve untuk menginformasikan "kerangka kerja pengujian" bahwa hook before telah selesai, dan pengujian dapat dimulai

Uji - Saya menjalankan dua kueri penyisipan menggunakan pegangan tx disimpan.

Setelah Hook - Saya menggunakan pegangan tx disimpan untuk mengembalikan transaksi, sehingga membatalkan semua perubahan yang dibuat selama pengujian. Karena data tidak pernah dilakukan, itu bahkan tidak dapat dilihat oleh atau mengganggu aktivitas pengujian lainnya.

Pada Concurrency

Knex

Knex memungkinkan Anda menentukan opsi untuk ukuran kolam koneksi. Jika Anda perlu memastikan semua kueri dalam transaksi berjalan pada koneksi yang sama (saya asumsikan demikian), maka Anda dapat melakukannya dengan menyetel ukuran kumpulan ke 1.

_Tapi tunggu ..._ lihat komentar ini di sumbernya :

// We need to make a client object which always acquires the same
// connection and does not release back into the pool.
function makeTxClient(trx, client, connection) {

Jika saya memahami ini dengan benar, itu berarti Knex dapat diandalkan untuk memastikan bahwa semua kueri dalam transaksi melalui koneksi yang sama, bahkan jika kumpulan Anda lebih besar dari 1! Jadi kita tidak perlu mengorbankan derajat konkurensi khusus ini untuk skenario kita.

BTW - Dokumen mungkin harus mencerminkan fakta penting dan menakjubkan ini.

Ava

_Saya tahu ini khusus Ava daripada khusus Knex, tetapi ini adalah kerangka kerja yang populer, dan pelajarannya dapat diterapkan secara luas ke sebagian besar kerangka kerja._

Ava menjalankan setiap testfile dalam proses terpisah secara bersamaan. Dalam setiap proses, ini juga menjalankan semua pengujian secara bersamaan. Kedua bentuk konkurensi dapat dinonaktifkan menggunakan opsi --serial CLI (yang membuat semuanya menjadi serial) atau pengubah .serial pada metode test (yang membuat serial pengujian yang ditandai sebelum menjalankan sisanya secara bersamaan ).

Bungkus

Saat saya mengumpulkan semua fakta ini:

  • Saya dapat membungkus setiap pengujian dalam sebuah transaksi, yang memastikan (a) data pengujian tidak bertabrakan (b) pembersihan pasca-pengujian otomatis tanpa pemotongan atau perpindahan. Faktanya, dengan menggunakan strategi ini, DB pengujian saya tidak akan pernah memiliki satu catatan pun yang bertahan untuk itu, selain mungkin data benih penting.

  • Saya dapat terus memanfaatkan konkurensi antar-testfile Ava, karena setiap testfile berjalan dalam proses yang terpisah, dan karenanya akan memiliki kumpulan koneksi Knex sendiri.

  • Saya dapat terus memanfaatkan konkurensi intra-testfile Ava jika saya memastikan bahwa kumpulan koneksi saya adalah> = jumlah pengujian dalam file tersebut. Ini seharusnya tidak menjadi masalah. Saya tidak melakukan banyak tes dalam satu file, yang tetap saya coba hindari. Selain itu, kumpulan dapat disetel dengan rentang seperti 1-10, jadi Anda tidak membuat koneksi yang tidak Anda perlukan, tetapi tidak perlu menyesuaikan konstanta di setiap file pengujian setiap kali Anda menambah atau menghapus pengujian.


Ingin sekali mendapatkan pemikiran orang lain, karena saya mencoba-coba di persimpangan sejumlah besar teknologi yang baru bagi saya pada saat yang sama ...

@odigity yup, transaksi di knex cukup banyak hanya menangani koneksi khusus di mana knex secara otomatis menambahkan BEGIN query ketika trx instance dibuat (sebenarnya transaksi di SQL umumnya hanya query yang akan ke koneksi yang sama yang diawali dengan BEGIN).

Jika knex tidak mengalokasikan koneksi untuk transaksi, maka transaksi tidak akan berfungsi sama sekali.

Menggunakan kunci uuid juga tidak buruk, perubahan tabrakan sangat tidak mungkin kecuali ada banyak baris. ("Jika Anda menggunakan UUID 128-bit, 'efek ulang tahun' memberi tahu kita bahwa tabrakan mungkin terjadi setelah Anda menghasilkan sekitar 2 ^ 64 kunci, asalkan Anda memiliki 128 bit entropi di setiap kunci.")

Saya kira Anda sudah menemukan jawabannya, jadi tutup ini 👍

Maaf untuk membuka kembali, tapi sekarang saya mengamati perilaku yang tidak terduga. Secara khusus, ini berfungsi ketika seharusnya tidak, yang berarti pemahaman saya perlu diperbaiki.

Jika saya menyetel ukuran kumpulan ke 1, membuka transaksi, lalu menjalankan kueri tanpa menggunakannya, waktu habis karena tidak dapat memperoleh koneksi - yang masuk akal, karena koneksi tersebut telah dikunci oleh transaksi.

Namun, jika saya menyetel ukuran kolam ke 1 dan menjalankan empat pengujian secara bersamaan, masing-masing:

  • membuka transaksi
  • menjalankan kueri
  • panggilan rollback di akhir

Mereka semua bekerja. Mereka seharusnya tidak berfungsi - setidaknya beberapa dari mereka harus dikunci oleh kelangkaan koneksi - tetapi semuanya berfungsi dengan baik, setiap saat.

Apakah Knex memiliki antrian bawaan untuk pertanyaan ketika tidak ada koneksi yang tersedia pada saat itu? Jika demikian, mengapa contoh pertama saya gagal, daripada menunggu transaksi selesai sebelum menjalankan kueri non-tx?

Atau apakah Knex entah bagaimana menggandakan beberapa transaksi bersamaan ke satu koneksi?

Atau Knex benar-benar membuat sub-transaksi pada pemanggilan ke-2, ke-3, dan ke-4? Jika demikian, itu mungkin secara acak akan menyebabkan hasil yang diharapkan ...

@odgity Dalam kasus pertama, Anda mengalami kebuntuan di sisi aplikasi (aplikasi Anda macet saat menunggu koneksi dan pemicu waktu habis perolehanConnection).

Dalam kasus kedua tes sebenarnya dijalankan secara serial, karena semua orang menunggu koneksi kecuali satu. Jika Anda memiliki cukup pengujian yang melakukan hal itu secara paralel atau kasus pengujian Anda sangat lambat, maka gainConnectionTimeout juga harus dipicu dalam kasus kedua.

Transaksi multiplexing dalam satu koneksi tidak dimungkinkan. Transaksi bersarang didukung oleh knex menggunakan savepoints di dalam transaksi. Jika Anda meminta transaksi baru dari pool, itu juga tidak akan terjadi.

Terima kasih, itu sangat membantu.

Meskipun saya masih sedikit bingung tentang mengapa mengeksekusi kueri terkunci ketika koneksi diambil oleh transaksi terbuka, tetapi mencoba membuka transaksi baru kedua dengan sabar menunggu dan kemudian selesai.

Jalankan kode Anda dengan DEBUG = knex: * environment variable dan Anda akan melihat apa yang dilakukan pool. Knex juga harus menunggu dalam kasus pertama hingga batas waktu "Saya tidak bisa mendapatkan koneksi" terjadi. Jadi jika transaksi Anda menunggu hingga koneksi kedua diperoleh, itu adalah kebuntuan level aplikasi karena kedua koneksi menunggu satu sama lain (saya tidak tahu apakah ini kasus Anda).

Saya menemukan utas ini sangat berguna. Sangat menyenangkan melihat bahwa orang lain juga peduli tentang menulis tes yang tidak mencemari status sistem. Saya memulai sebuah proyek yang memungkinkan orang untuk menulis tes untuk kode yang menggunakan knex yang akan rollback setelah tes selesai.

https://github.com/bas080/knest

@ bas080 dalam kasus umum yang mendekati membatasi hal-hal yang dapat Anda uji (mengizinkan pengujian untuk menggunakan hanya satu transaksi). Ini akan mencegah kode pengujian yang menggunakan beberapa koneksi / transaksi bersamaan. Juga seseorang tidak dapat menguji kode yang melakukan komit implisit (meskipun bukan kasus yang sangat umum) dengan cara ini.

Saya tahu menggunakan transaksi untuk mengatur ulang status setelah menjalankan pengujian adalah pola yang cukup umum, yang ingin saya tekankan adalah bahwa hanya menggunakan pendekatan itu mencegah seseorang untuk menguji hal-hal tertentu.

Saya selalu lebih suka memotong dan mengisi kembali DB setelah setiap tes yang mengubah data atau setelah beberapa rangkaian tes yang bergantung satu sama lain (beberapa kali saya melakukan ini untuk alasan kinerja jika mengisi terlalu lama seperti lebih dari 50ms).

hai, maaf untuk membuka kembali masalah ini tetapi saya memulai proyek baru yang merupakan cli untuk knex untuk _seed beberapa database dengan data palsu, _ saya ingin Anda melihatnya dan membantu saya dengan beberapa kontribusi

Untuk pengujian unit, saya hanya memeriksa bahwa kueri yang dijalankan oleh Knex dari pembungkus SQL saya dibentuk dengan benar, dengan menggunakan toString() di akhir rantai kueri. Untuk pengujian integrasi, saya telah menggunakan strategi yang telah disebutkan di atas - yaitu cycle: rollback -> migrate -> seed, sebelum setiap pengujian. Dapat dimaklumi bahwa ini mungkin terlalu lambat jika Anda tidak dapat menyimpan data seed Anda dalam jumlah kecil, tetapi mungkin cocok untuk orang lain.

yaitu ke siklus: rollback -> migrasi -> seed, sebelum setiap tes.

Itu cara yang sangat buruk untuk melakukannya. Menjalankan migrasi bolak-balik membutuhkan waktu ratusan milidetik, yang mana ini terlalu lambat. Anda harus menjalankan migrasi hanya sekali untuk keseluruhan rangkaian pengujian dan kemudian sebelum pengujian cukup potong semua tabel dan masukkan data pengujian yang sesuai. Ini dapat dilakukan dengan mudah 100x lebih cepat daripada menggulung / membuat ulang seluruh skema.

Anda dapat menggunakan pembersih knex untuk memotong semua tabel dengan mudah:

knexCleaner
    .clean(knex, { ignoreTables: ['knex_migrations', 'knex_migrations_lock'] })
    .then(() => knex.seed.run())

Perhatikan bahwa tidak perlu menggunakan bagian ignoreTables jika Anda menjalankan migrasi di awal setiap rangkaian pengujian yang dijalankan. Ini hanya diperlukan jika Anda menjalankan migrasi secara manual di database pengujian Anda.

@ricardograca Apakah ini menangani kasus dengan kunci asing dengan baik? (artinya pembersihan tidak akan gagal karena urutan penghapusan salah)

Jika tidak, itu mudah diperbaiki (hanya perlu memotong semua tabel dengan satu kueri) :)

@elhigu Bagaimana Anda bisa melakukan itu?

@kibertoad Ya, ini menangani batasan kunci asing dengan baik dan menghapus semuanya.

@odigity gimana kalo kita mau uji struktur seperti itu:

// controller.js
const users = require('./usersModel.js');

module.exports.addUser = async ({ token, user }) => {
  // check token, or other logic
  return users.add(user);
};

// usersModel.js
const db = require('./db');

module.exports.add = async user => db('users').insert(user);

// db.js
module.exports = require('knex')({ /* config */});

Saya cara Anda semua fungsi harus memiliki argumen tambahan (misalnya trx ) untuk meneruskan transaksi ke pembuat kueri yang sebenarnya.
https://knexjs.org/#Builder -transacting

Menurut saya cara yang benar harus seperti itu:

  1. Buat trx di beforeEach .
  2. Entah bagaimana menyuntikkannya. Dalam contoh saya require('./db') sould mengembalikan nilai trx.
  3. Lakukan tes.
  4. Rollback trx di 'afterEach'.

Tapi, saya tidak tahu apakah itu mungkin dengan knex?
Bagaimana jika kode menggunakan transaksi antoher?

Juga opsi lain: mungkin ada beberapa fungsi yang mulai mengeksekusi kueri. Jadi kita bisa menggantinya untuk memaksa berjalan dalam transaksi percobaan.

Setelah seharian membaca kode knex, saya mencoba pendekatan ini:

test.beforeEach(async t => {
    // if we use new 0.17 knex api knex.transaction().then - we can not handle rollback error
    // so we need to do it in old way
    // and add empty .catch to prevent unhandled rejection
    t.context.trx = await new Promise(resolve => db.transaction(trx => resolve(trx)).catch(() => {}));
    t.context.oldRunner = db.client.runner;
    db.client.runner = function(builder) {
        return t.context.oldRunner.call(t.context.trx.client, builder);
    };
    t.context.oldRaw = db.raw;
    db.raw = function(...args) {
        return t.context.oldRaw.call(this, ...args).transacting(t.context.trx);
    };
});

test.afterEach(async t => {
    db.raw = t.context.oldRaw;
    db.client.runner = t.context.oldRunner;
    await t.context.trx.rollback();
});

Dan itu berhasil. Jadi saya mengganti metode .raw dan .client.runner . .client.runner memanggil secara internal ketika Anda .then pembuat kueri. db dalam fungsi ini adalah klien knex knex({ /* config */}) .

@Niklv seperti yang sudah saya jelaskan di sini; menggunakan transaksi untuk mengatur ulang data pengujian umumnya merupakan ide yang buruk dan saya bahkan akan menganggapnya sebagai anti-pola. Begitu juga dengan bagian internal knex yang utama. Truncate + repopulate db pada setiap tes atau untuk serangkaian tes adalah rekomendasi. Tidak perlu banyak milidetik untuk melakukannya jika data pengujian berukuran wajar.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

marianomerlo picture marianomerlo  ·  3Komentar

nklhrstv picture nklhrstv  ·  3Komentar

mattgrande picture mattgrande  ·  3Komentar

fsebbah picture fsebbah  ·  3Komentar

mishitpatel picture mishitpatel  ·  3Komentar