Apabila unit menguji kod dunia nyata, banyak situasi membuat ujian sukar ditulis. Bagaimana untuk memeriksa sama ada fungsi dipanggil? Bagaimana untuk menguji panggilan Ajax? Atau gunakan kod
untuk menguji pendirian setTimeout
-menggantikan kod untuk memudahkan untuk diuji dalam ujian yang sukar.
Selama bertahun-tahun, Sinon.js telah menjadi standard sebenar untuk membuat ujian stand-in dalam ujian JavaScript. Ia adalah alat penting untuk mana -mana pemaju JavaScript yang menulis ujian, kerana tanpa itu, hampir mustahil untuk menulis ujian untuk aplikasi sebenar.
Baru -baru ini, sebuah perpustakaan baru yang dipanggil TestDouble.js muncul. Ia mempunyai ciri yang sama yang ditetapkan untuk sinon.js, kecuali terdapat beberapa perbezaan di sana sini.
Dalam artikel ini, kita akan meneroka apa yang disediakan oleh sinon.js dan testdouble.js dan membandingkan kebaikan dan keburukan masing -masing. Adakah sinon.js masih menjadi pilihan yang lebih baik, atau bolehkah pencabar menang?
Nota: Jika anda tidak biasa dengan ujian pendirian, disarankan agar anda membaca tutorial Sinon.js saya terlebih dahulu. Ini akan membantu anda memahami dengan lebih baik konsep yang akan kami bincangkan di sini.
Untuk memastikan pemahaman yang mudah tentang apa yang sedang dibincangkan, inilah gambaran ringkas mengenai istilah yang digunakan. Ini adalah definisi sinon.js dan mungkin berbeza sedikit di tempat lain.
Harus diingat bahawa salah satu matlamat TestDouble.js adalah untuk mengurangkan kekeliruan antara istilah ini.
Mari kita lihat perbandingan penggunaan asas antara sinon.js dan testdouble.js.
Sinon mempunyai tiga konsep pendirian ujian yang berbeza: mata-mata, stub, dan mengejek. Ideanya ialah masing -masing mewakili senario penggunaan yang berbeza. Ini menjadikan perpustakaan lebih akrab kepada orang -orang dari bahasa lain atau yang telah membaca buku menggunakan istilah yang sama, seperti mod ujian Xunit. Tetapi sebaliknya, ketiga -tiga konsep ini juga boleh membuat Sinon lebih sukar difahami ketika pertama kali digunakan. Ini adalah contoh asas penggunaan sinon:
// 以下是查看函数调用的参数的方法: var spy = sinon.spy(Math, 'abs'); Math.abs(-10); console.log(spy.firstCall.args); // 输出:[ -10 ] spy.restore(); // 以下是控制函数执行方式的方法: var stub = sinon.stub(document, 'createElement'); stub.returns('not an html element'); var x = document.createElement('div'); console.log(x); // 输出:'not an html element' stub.restore();
Sebaliknya, testdouble.js memilih API yang lebih mudah. Daripada menggunakan konsep seperti mata -mata atau stub, ia menggunakan bahasa yang pemaju JavaScript lebih akrab dengan, seperti td.function
, td.object
dan td.replace
. Ini menjadikan testdouble berpotensi lebih mudah untuk dimulakan dan lebih sesuai untuk tugas -tugas tertentu. Tetapi sebaliknya, beberapa kegunaan yang lebih maju mungkin tidak mungkin (yang kadang -kadang disengajakan).
Berikut adalah cara menggunakan testdouble.js:
// 以下是查看函数调用的参数的方法: var abs = td.replace(Math, 'abs'); Math.abs(-10); var explanation = td.explain(abs); console.log(explanation.calls[0].args); // 输出:[ -10 ] // 以下是控制函数执行方式的方法: var createElement = td.replace(document, 'createElement'); td.when(createElement(td.matchers.anything())).thenReturn('not an html element'); var x = document.createElement('div'); console.log(x); // 输出:'not an html element' // testdouble 使用一次调用重置所有测试替身,无需单独清理 td.reset();
TestDouble menggunakan bahasa yang lebih mudah. Kami "menggantikan" fungsi dan bukannya "Stub". Kami memerlukan fungsi "tafsiran" testdouble untuk mendapatkan maklumat daripadanya. Selain itu, ia agak serupa dengan Sinon setakat ini.
Ini juga meluas untuk mencipta ujian "tanpa nama":
var x = sinon.stub();
dan
var x = td.function();
Sinon's Spies and Stubs mempunyai atribut yang memberikan lebih banyak maklumat tentang mereka. Sebagai contoh, Sinon menyediakan atribut seperti stub.callCount
dan stub.args
. Dalam kes TestDouble, kami mendapat maklumat ini dari td.explain
:
// 我们也可以为测试替身命名 var x = td.function('hello'); x('foo', 'bar'); td.explain(x); console.log(x); /* 输出: { name: 'hello', callCount: 1, calls: [ { args: ['foo', 'bar'], context: undefined } ], description: 'This test double `hello` has 0 stubbings and 1 invocations.\n\nInvocations:\n - called with `("foo", "bar")`.', isTestDouble: true } */
Salah satu perbezaan terbesar adalah berkaitan dengan bagaimana stub ditetapkan dan pengesahan dilakukan. Dengan Sinon, anda boleh menghubungkan arahan selepas stub dan menggunakan pernyataan untuk mengesahkan hasilnya. testdouble.js hanya menunjukkan kepada anda bagaimana anda ingin memanggil fungsi -atau bagaimana untuk "berlatih" panggilan fungsi.
var x = sinon.stub(); x.withArgs('hello', 'world').returns(true); var y = sinon.stub(); sinon.assert.calledWith(y, 'foo', 'bar');
dan
var x = td.function(); td.when(x('hello', 'world')).thenReturn(true); var y = td.function(); td.verify(y('foo', 'bar'));
Ini menjadikan API TestDouble lebih mudah difahami, kerana anda tidak perlu tahu apa tindakan yang boleh dikaitkan pada kapan.
Pada tahap yang tinggi, kedua -dua perpustakaan agak serupa. Tetapi bagaimana dengan tugas ujian biasa yang mungkin perlu anda lakukan dalam projek sebenar? Mari kita lihat di mana beberapa perbezaan mula muncul.
Perkara pertama yang perlu diperhatikan ialah testdouble.js tidak mempunyai konsep "mata -mata". Walaupun sinon.js membolehkan kami menggantikan panggilan fungsi untuk mendapatkan maklumat dari mereka sambil mengekalkan tingkah laku lalai fungsi, ini tidak mungkin dalam testdouble.js. Apabila anda menggantikan fungsi dengan TestDouble, ia sentiasa kehilangan tingkah laku lalainya.
Tetapi ini tidak semestinya masalah. Penggunaan mata -mata yang paling biasa adalah menggunakannya untuk mengesahkan bahawa panggilan balik dipanggil, yang mudah dicapai dengan td.function
:
var spy = sinon.spy(); myAsyncFunction(spy); sinon.assert.calledOnce(spy);
dan
var spy = td.function(); myAsyncFunction(spy); td.verify(spy());
Walaupun ia bukan masalah besar, masih penting untuk diperhatikan perbezaan ini antara kedua -dua perpustakaan, jika tidak, anda mungkin terkejut jika anda mengharapkan dapat menggunakan mata -mata dalam testdouble.js dengan cara yang lebih spesifik.
Perbezaan kedua yang akan anda hadapi ialah TestDouble adalah lebih ketat pada input.
Stubs dan pernyataan Sinon membolehkan anda menjadi tidak tepat dengan parameter yang disediakan. Ini paling mudah untuk digambarkan dengan contoh:
var stub = sinon.stub(); stub.withArgs('hello').returns('foo'); console.log(stub('hello', 'world')); // 输出:'foo' sinon.assert.calledWith(stub, 'hello'); // 没有错误
dan
// 以下是查看函数调用的参数的方法: var spy = sinon.spy(Math, 'abs'); Math.abs(-10); console.log(spy.firstCall.args); // 输出:[ -10 ] spy.restore(); // 以下是控制函数执行方式的方法: var stub = sinon.stub(document, 'createElement'); stub.returns('not an html element'); var x = document.createElement('div'); console.log(x); // 输出:'not an html element' stub.restore();
Secara lalai, Sinon tidak peduli berapa banyak parameter tambahan yang diberikan kepada fungsi tersebut. Walaupun ia menyediakan fungsi seperti sinon.assert.calledWithExactly
, ia tidak disyorkan sebagai nilai lalai dalam dokumentasi. Fungsi seperti stub.withArgs
juga tidak mempunyai varian "tepat".
Parameter sewenang -wenang boleh ditentukan dalam testdouble.js, tetapi ini bukan nilai lalai:
// 以下是查看函数调用的参数的方法: var abs = td.replace(Math, 'abs'); Math.abs(-10); var explanation = td.explain(abs); console.log(explanation.calls[0].args); // 输出:[ -10 ] // 以下是控制函数执行方式的方法: var createElement = td.replace(document, 'createElement'); td.when(createElement(td.matchers.anything())).thenReturn('not an html element'); var x = document.createElement('div'); console.log(x); // 输出:'not an html element' // testdouble 使用一次调用重置所有测试替身,无需单独清理 td.reset();
, tingkah laku sama dengan sinon.js. ignoreExtraArgs: true
var x = sinon.stub();
var x = td.function();
nota : Anda boleh menggunakan sinon-as-dijanjikan untuk memasukkan fungsi mudah yang sama dalam Sinon 1.x. Sinon 2.0 dan versi yang lebih baru termasuk sokongan janji dalam bentuk dan stub.resolves
. stub.rejects
Sinon menggunakan
untuk membuat panggilan stub fungsi pertama stub.yields
diterima sebagai parameter.
// 我们也可以为测试替身命名 var x = td.function('hello'); x('foo', 'bar'); td.explain(x); console.log(x); /* 输出: { name: 'hello', callCount: 1, calls: [ { args: ['foo', 'bar'], context: undefined } ], description: 'This test double `hello` has 0 stubbings and 1 invocations.\n\nInvocations:\n - called with `("foo", "bar")`.', isTestDouble: true } */
. Anda tidak perlu menentukannya semasa latihan panggilan:
Apa yang membuat sokongan panggil balik testDoble lebih kuat ialah anda boleh dengan mudah menentukan tingkah laku senario dengan pelbagai panggilan balik atau pesanan panggilan balik yang berbeza.var x = sinon.stub(); x.withArgs('hello', 'world').returns(true); var y = sinon.stub(); sinon.assert.calledWith(y, 'foo', 'bar');
Katakan kita mahu menelefon
...
callback1
var x = td.function(); td.when(x('hello', 'world')).thenReturn(true); var y = td.function(); td.verify(y('foo', 'bar'));
. Ini memberitahu TestDouble parameter yang kita mahu gunakan sebagai panggilan balik. td.callback
td.when
menggunakan sinon, anda juga boleh mengubah tingkah laku:
Dalam kes ini, kami menggunakan
var spy = sinon.spy(); myAsyncFunction(spy); sinon.assert.calledOnce(spy);
. Kami perlu menyediakan indeks panggilan khusus untuk menjadikannya berfungsi, yang boleh menjadi agak rumit, terutamanya pada fungsi dengan banyak parameter. callsArgWith
yields
Bagaimana jika kita mahu memanggil
panggilan balik dengan nilai tertentu?
Dengan Sinon, ini hanya mustahil. Anda boleh menghubungkan pelbagai panggilan kevar spy = td.function(); myAsyncFunction(spy); td.verify(spy());
callsArgWith
testdouble.js mempunyai penggantian modul terbina dalam
td.replace
Ini terutamanya berguna jika anda mempunyai modul yang secara langsung mengeksport fungsi yang perlu diganti:
Jika kita mahu menggantikannya dengan testdouble, kita boleh menggunakan
var stub = sinon.stub(); stub.withArgs('hello').returns('foo'); console.log(stub('hello', 'world')); // 输出:'foo' sinon.assert.calledWith(stub, 'hello'); // 没有错误
// 以下是查看函数调用的参数的方法: var spy = sinon.spy(Math, 'abs'); Math.abs(-10); console.log(spy.firstCall.args); // 输出:[ -10 ] spy.restore(); // 以下是控制函数执行方式的方法: var stub = sinon.stub(document, 'createElement'); stub.returns('not an html element'); var x = document.createElement('div'); console.log(x); // 输出:'not an html element' stub.restore();
Walaupun sinon.js boleh menggantikan fungsi ahli objek, ia tidak dapat menggantikan modul seperti ini. Untuk melakukan ini apabila menggunakan Sinon, anda perlu menggunakan modul lain, seperti Proxyquire atau Rewire.
// 以下是查看函数调用的参数的方法: var abs = td.replace(Math, 'abs'); Math.abs(-10); var explanation = td.explain(abs); console.log(explanation.calls[0].args); // 输出:[ -10 ] // 以下是控制函数执行方式的方法: var createElement = td.replace(document, 'createElement'); td.when(createElement(td.matchers.anything())).thenReturn('not an html element'); var x = document.createElement('div'); console.log(x); // 输出:'not an html element' // testdouble 使用一次调用重置所有测试替身,无需单独清理 td.reset();
Satu lagi perkara yang anda perlu perhatikan mengenai penggantian modul ialah testdouble.js secara automatik akan menggantikan keseluruhan modul. Jika ia merupakan eksport fungsi seperti contoh di sini, ia menggantikan fungsi. Jika ia adalah objek yang mengandungi pelbagai fungsi, ia menggantikan semuanya. Pembina dan kelas ES6 juga disokong. Kedua -dua Proxyquire dan Rewire memerlukan anda menentukan secara individu apa dan cara menggantikannya.
Jika anda menggunakan pemasa emulasi Sinon, emulasi xmlhttprequest, atau pelayan emulasi, anda akan melihat bahawa mereka tidak wujud dalam testdouble.
Pemasa emulasi boleh digunakan sebagai plugin, tetapi fungsi XMLHTTPREQUESTS dan AJAX perlu dikendalikan dengan cara yang berbeza.
Penyelesaian mudah adalah untuk menggantikan fungsi Ajax yang anda gunakan, mis
$.post
var x = sinon.stub();
atau:
var x = td.function();
// 我们也可以为测试替身命名 var x = td.function('hello'); x('foo', 'bar'); td.explain(x); console.log(x); /* 输出: { name: 'hello', callCount: 1, calls: [ { args: ['foo', 'bar'], context: undefined } ], description: 'This test double `hello` has 0 stubbings and 1 invocations.\n\nInvocations:\n - called with `("foo", "bar")`.', isTestDouble: true } */
, jika tidak, mudah untuk tidak sengaja meninggalkan stub atau mata -mata, yang boleh menyebabkan masalah dengan ujian lain. Ini boleh membawa kepada kegagalan cascade yang sukar untuk dikesan.
var x = sinon.stub(); x.withArgs('hello', 'world').returns(true); var y = sinon.stub(); sinon.assert.calledWith(y, 'foo', 'bar');
. Kaedah yang disyorkan adalah memanggilnya dalam cangkuk sinon.test
:
td.reset()
Ini sangat memudahkan persediaan ujian stand-in dan membersihkan selepas ujian, mengurangkan kemungkinan kesilapan yang sukar untuk dilancarkan. afterEach
var x = td.function(); td.when(x('hello', 'world')).thenReturn(true); var y = td.function(); td.verify(y('foo', 'bar'));
kita kini memahami fungsi kedua -dua perpustakaan ini. Kedua -duanya menawarkan satu set ciri yang sama, tetapi mereka mempunyai idea reka bentuk yang berbeza antara satu sama lain. Bolehkah kita memecahkannya ke dalam kelebihan dan kekurangan?
Kelemahannya ialah ia meningkatkan kerumitan. Walaupun fleksibiliti membolehkan pakar melakukan lebih banyak perkara, ini bermakna tugas -tugas tertentu lebih kompleks daripada dalam testdouble.js. Ia juga mungkin mempunyai keluk pembelajaran yang lebih curam bagi mereka yang baru untuk menguji konsep pendirian. Malah, walaupun seseorang yang biasa dengannya kerana saya mungkin mempunyai masa yang sukar untuk menerangkan secara terperinci beberapa perbezaan antara
dan!
testdouble.js memilih antara muka yang lebih mudah. Kebanyakan kandungannya agak mudah dan mudah digunakan dan terasa lebih sesuai untuk JavaScript, sementara Sinon.js kadang -kadang terasa seperti ia direka untuk bahasa lain. Terima kasih kepada ini dan beberapa prinsip reka bentuk, lebih mudah bagi pemula untuk memulakan, dan bahkan penguji yang berpengalaman akan mendapati banyak tugas yang lebih mudah untuk diselesaikan. Sebagai contoh, TestDouble menggunakan API yang sama untuk menubuhkan ujian stand-in dan mengesahkan hasil. Ia juga mungkin kurang terdedah kepada kesilapan kerana mekanisme pembersihan yang lebih mudah.
TestDouble Masalah terbesar disebabkan oleh beberapa prinsip reka bentuknya. Sebagai contoh, kekurangan mata -mata yang lengkap mungkin menjadikannya mustahil bagi sesetengah orang yang lebih suka menggunakan mata -mata di atas stub. Ini sebahagian besarnya adalah persoalan pendapat dan anda mungkin tidak menemui masalah sama sekali. Selain itu, walaupun testdouble.js adalah perpustakaan yang dikemas kini, ia menyediakan beberapa persaingan yang serius untuk sinon.js.
Berikut adalah perbandingan dengan fungsi:
功能 | Sinon.js | testdouble.js |
---|---|---|
间谍 | 是 | 否 |
存根 | 是 | 是 |
延迟存根结果 | 否 | 是 |
模拟 | 是 | 是1 |
Promise 支持 | 是(在 2.0 中) | 是 |
时间辅助函数 | 是 | 是(通过插件) |
Ajax 辅助函数 | 是 | 否(改为替换函数) |
模块替换 | 否 | 是 |
内置断言 | 是 | 是 |
匹配器 | 是 | 是 |
自定义匹配器 | 是 | 是 |
参数捕获器 | 否2 | 是 |
代理测试替身 | 否 | 是 |
td.replace(someObject)
. stub.yield
(tidak boleh dikelirukan dengan stub.yields
). sinon.js dan testdouble.js kedua -duanya menyediakan satu set ciri yang serupa. Dalam hal ini, tidak jelas.
Perbezaan terbesar antara keduanya adalah API mereka. Sinon.js mungkin sedikit lebih lama dan menawarkan banyak pilihan tentang cara melakukan sesuatu. Ini mungkin kebaikan dan keburukannya. testdouble.js mempunyai API yang lebih leaner, yang menjadikannya lebih mudah untuk dipelajari dan digunakan, tetapi disebabkan reka bentuk yang lebih sewenang -wenangnya, ada yang mungkin mendapati ia bermasalah.
Adakah anda bersetuju dengan prinsip reka bentuk TestDouble? Jika ya, maka tidak ada sebab untuk tidak menggunakannya. Saya telah menggunakan sinon.js dalam banyak projek dan saya dengan selamat boleh mengatakan bahawa testdouble.js melakukan sekurang -kurangnya 95% daripada kerja yang saya lakukan di sinon.js dan baki 5% boleh dilakukan dengan beberapa penyelesaian yang mudah.
Jika anda mendapati sinon.js sukar digunakan, atau mencari lebih banyak "javascript-style" testdouble.js mungkin untuk anda juga. Malah orang seperti saya yang menghabiskan banyak masa belajar menggunakan sinon, saya cenderung mencadangkan untuk mencuba testdouble.js dan lihat jika anda suka.
Walau bagaimanapun, beberapa aspek testdouble.js boleh menyebabkan sakit kepala bagi mereka yang mempunyai pengetahuan tentang sinon.js atau penguji yang berpengalaman. Sebagai contoh, kekurangan mata -mata yang lengkap mungkin menjadi faktor penentu. Sinon.js masih merupakan pilihan yang baik untuk pakar dan mereka yang mahukan fleksibiliti yang paling.Jika anda ingin mengetahui lebih lanjut mengenai cara menggunakan ujian stand-in dalam amalan, lihat panduan Sinon.js percuma saya. Walaupun ia menggunakan sinon.js, anda juga boleh menggunakan teknik dan amalan terbaik yang sama untuk testdouble.js.
ada masalah? Komen? Adakah anda sudah menggunakan testdouble.js? Selepas membaca artikel ini, adakah anda menganggapnya mencubanya? Tolong beritahu saya dalam komen di bawah.
Artikel ini dikaji semula oleh James Wright, Joan Yin, Christian Johansen dan Justin Searls. Terima kasih kepada semua pengulas rakan sebaya untuk mendapatkan kandungan SitePoint dengan sebaik -baiknya!
sinon.js dan testdouble.js adalah perpustakaan ujian JavaScript yang popular, tetapi mereka mempunyai beberapa perbezaan utama. Sinon.js terkenal dengan set ciri yang kaya, termasuk mata -mata, stub, dan simulasi, serta utiliti untuk meniru pemasa dan XHR. Ia adalah alat yang serba boleh yang boleh digunakan bersempena dengan rangka kerja ujian. Sebaliknya, testdouble.js adalah perpustakaan minimalis yang memberi tumpuan kepada menyediakan API yang mudah dan intuitif untuk menguji pendirian, yang merupakan alternatif kepada bahagian-bahagian sistem yang akan diuji. Ia tidak termasuk utiliti untuk meniru pemasa atau XHRS, tetapi ia direka untuk mudah digunakan dan difahami, jadi ia adalah pilihan yang baik bagi mereka yang lebih suka kaedah ujian yang lebih leaner.
sinon.js dan testdouble.js boleh dipasang melalui NPM (Pengurus Pakej Node.js). Untuk sinon.js, anda boleh menggunakan arahan npm install sinon
. Untuk testdouble.js, perintah itu npm install testdouble
. Selepas pemasangan, anda boleh menggunakan const sinon = require('sinon')
dan const td = require('testdouble')
untuk memperkenalkannya dalam fail ujian anda.
Ya, sinon.js dan testdouble.js boleh digunakan serentak dalam projek yang sama. Mereka semua direka untuk menjadi sangat mudah dan berfungsi dengan baik dengan perpustakaan lain. Walau bagaimanapun, ingat bahawa mereka mempunyai ciri -ciri bertindih, jadi menggunakannya pada masa yang sama boleh menyebabkan kekeliruan. Ia biasanya disyorkan untuk memilih salah satu daripada mereka berdasarkan keperluan dan keutamaan khusus anda.
Dalam sinon.js, anda boleh menggunakan sinon.spy()
untuk membuat mata -mata. Fungsi ini mengembalikan objek pengintip yang merekodkan semua panggilan yang dibuat kepadanya, termasuk parameter, nilai pulangan, dan pengecualian. Dalam testdouble.js, anda boleh membuat mata -mata menggunakan td.function()
. Fungsi ini mengembalikan fungsi berdiri sendiri yang merekodkan semua panggilan, termasuk parameter.
Dalam sinon.js, anda boleh membuat stub menggunakan sinon.stub()
. Fungsi ini mengembalikan objek stub yang berkelakuan seperti mata -mata, tetapi ia juga membolehkan anda menentukan tingkah lakunya, seperti menentukan nilai pulangan atau membuang pengecualian. Dalam testdouble.js, anda boleh membuat stub menggunakan td.when()
. Fungsi ini membolehkan anda menentukan tingkah laku anda apabila memanggil ujian siap sedia dengan parameter tertentu.
Dalam sinon.js, anda boleh menggunakan kaedah seperti spy.called
, spy.calledWith()
, dan spy.returned()
untuk mengesahkan mata -mata atau stub. Dalam testdouble.js, anda boleh menggunakan td.verify()
untuk menegaskan sama ada ujian siap sedia dipanggil dalam beberapa cara.
sinon.js mempunyai ciri yang lebih komprehensif berbanding dengan testdouble.js. Ia termasuk utiliti untuk meniru pemasa dan XHR, yang sangat berguna untuk menguji jenis kod tertentu. Ia juga digunakan secara meluas dan mempunyai komuniti yang lebih besar, yang bermaksud lebih banyak sumber dan sokongan dapat diperolehi.
testdouble.js mempunyai API yang lebih mudah dan lebih intuitif daripada sinon.js. Ia direka untuk menjadi mudah digunakan dan difahami, jadi ia adalah pilihan yang baik bagi mereka yang lebih suka kaedah ujian yang lebih diselaraskan. Ia juga menggalakkan amalan ujian yang baik dengan menjadikannya sukar untuk menyalahgunakan ujian.
Ya, sinon.js dan testdouble.js kedua -duanya direka dengan sangat kemas dan berfungsi dengan baik dengan kerangka ujian lain. Mereka boleh digunakan dengan mana-mana rangka kerja ujian yang dibolehkan JavaScript.
Ya, sinon.js dan testdouble.js mempunyai banyak dokumentasi di laman web rasmi mereka. Terdapat juga banyak tutorial, catatan blog, dan kursus dalam talian yang meliputi kandungan mendalam dari perpustakaan ini.
Atas ialah kandungan terperinci TOOL TOOL UJIAN JAVASCRIPT: SINON.JS VS TESTDOUBLE.JS. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!