QUnit, dibangunkan oleh pasukan jQuery, ialah rangka kerja yang sangat baik untuk ujian unit JavaScript. Dalam tutorial ini, saya akan menerangkan apa sebenarnya QUnit dan mengapa anda perlu mengambil berat tentang menguji kod anda dengan teliti.
QUnit ialah rangka kerja ujian unit JavaScript yang berkuasa yang membantu anda nyahpepijat kod anda. Ia ditulis oleh ahli pasukan jQuery dan merupakan suite ujian rasmi untuk jQuery. Tetapi QUnit cukup umum untuk menguji mana-mana kod JavaScript biasa, dan juga JavaScript sisi pelayan melalui enjin JavaScript tertentu seperti Rhino atau V8.
Jika anda tidak biasa dengan konsep "unit testing", jangan risau. Ia tidak sukar untuk difahami:
Dalam pengaturcaraan komputer, ujian unit ialah kaedah pengesahan dan pengesahan perisian di mana pengaturcara menguji sama ada unit individu kod sumber sesuai untuk digunakan. Unit ialah bahagian terkecil yang boleh diuji bagi aplikasi. Dalam pengaturcaraan prosedur, unit boleh menjadi fungsi atau prosedur individu.
Kandungan ini dipetik daripada Wikipedia. Ringkasnya, anda menulis ujian untuk setiap ciri kod anda, dan jika semua ujian ini lulus, anda boleh yakin bahawa kod anda akan bebas pepijat (kebanyakannya bergantung pada seberapa teliti ujian anda).
Jika anda belum menulis sebarang ujian unit sebelum ini, anda mungkin hanya menggunakan kod terus ke tapak web, klik sebentar untuk melihat jika sebarang masalah timbul dan cuba membaikinya apabila anda mendapati mereka. Terdapat banyak masalah dengan pendekatan ini.
Pertama sekali, ia sangat membosankan. Mengklik sebenarnya bukan satu tugas yang mudah kerana anda perlu memastikan semuanya diklik dan kemungkinan besar anda akan terlepas satu atau dua perkara. Kedua, tiada apa yang anda lakukan untuk ujian boleh diguna semula, yang bermaksud mencari regresi tidak mudah. Apakah regresi? Bayangkan anda menulis beberapa kod, mengujinya, membetulkan sebarang pepijat yang anda temui, dan kemudian mengeluarkannya. Pengguna kemudian menghantar beberapa maklum balas tentang pepijat baharu dan meminta beberapa ciri baharu. Anda kembali ke dalam kod, betulkan pepijat baharu ini dan tambahkan ciri baharu ini. Apa yang mungkin berlaku seterusnya ialah beberapa pepijat lama muncul semula, ini dipanggil "regresi". Lihat, sekarang anda perlu mengklik sekali lagi, kemungkinan besar anda tidak akan menemui pepijat lama ini lagi dan walaupun anda melakukannya, ia akan mengambil sedikit masa sebelum anda mengetahui bahawa masalah itu disebabkan oleh regresi. Dengan ujian unit, anda boleh menulis ujian untuk mencari pepijat dan setelah kod itu diubah suai, anda boleh menapisnya melalui ujian sekali lagi. Jika regresi berlaku, sesetengah ujian pasti akan gagal, dan anda boleh melihatnya dengan mudah, mengetahui bahagian mana kod yang mengandungi ralat. Memandangkan anda tahu perkara yang baru anda ubah suai, anda boleh membetulkannya dengan mudah.
Satu lagi kelebihan ujian unit terpakai terutamanya pada pembangunan web: ia memudahkan ujian untuk keserasian merentas pelayar. Jalankan sahaja ujian pada penyemak imbas yang berbeza, dan jika berlaku masalah dengan satu penyemak imbas, anda boleh membetulkannya dan menjalankan ujian sekali lagi, memastikan ia tidak memperkenalkan regresi pada penyemak imbas lain. Setelah semua penyemak imbas sasaran lulus ujian, anda boleh yakin bahawa mereka semua disokong.
Saya ingin menyebut salah satu projek John Resig: TestSwarm. Dengan menjadikannya diedarkan, ia membawa ujian unit JavaScript ke peringkat seterusnya. Ia adalah tapak web dengan banyak ujian, sesiapa sahaja boleh pergi ke sana, menjalankan beberapa ujian, dan kemudian mengembalikan hasilnya kepada pelayan. Dengan cara ini kod boleh diuji dengan cepat merentas pelayar yang berbeza dan juga platform yang berbeza.
Jadi bagaimana untuk menulis ujian unit menggunakan QUnit? Mula-mula anda perlu menyediakan persekitaran ujian:
<!DOCTYPE html> <html> <head> <title>QUnit Test Suite</title> <link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" media="screen"> <script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script> <!-- Your project file goes here --> <script type="text/javascript" src="myProject.js"></script> <!-- Your tests file goes here --> <script type="text/javascript" src="myTests.js"></script> </head> <body> <h1 id="qunit-header">QUnit Test Suite</h1> <h2 id="qunit-banner"></h2> <div id="qunit-testrunner-toolbar"></div> <h2 id="qunit-userAgent"></h2> <ol id="qunit-tests"></ol> </body> </html>
Seperti yang anda lihat, versi terurus rangka kerja QUnit digunakan di sini.
Kod yang anda ingin uji hendaklah diletakkan ke dalam myProject.js dan ujian anda hendaklah dimasukkan ke dalam myTests.js. Untuk menjalankan ujian ini, cuma buka fail HTML ini dalam penyemak imbas anda. Kini tiba masanya untuk menulis beberapa ujian.
Blok binaan ujian unit ialah penegasan.
Penegasan ialah pernyataan yang meramalkan hasil yang dikembalikan oleh kod. Jika ramalan itu salah, dakwaan itu gagal dan anda tahu sesuatu telah berlaku.
Untuk menjalankan penegasan, anda harus memasukkannya ke dalam kes ujian:
// Let's test this function function isEven(val) { return val % 2 === 0; } test('isEven()', function() { ok(isEven(0), 'Zero is an even number'); ok(isEven(2), 'So is two'); ok(isEven(-4), 'So is negative four'); ok(!isEven(1), 'One is not an even number'); ok(!isEven(-7), 'Neither is negative seven'); })
Di sini kami mentakrifkan fungsi Genap, yang mengesan sama ada nombor genap, dan kami ingin menguji fungsi ini untuk memastikan ia tidak mengembalikan jawapan yang salah.
Kami mula-mula memanggil test(), yang membina kes ujian; parameter pertama ialah rentetan yang akan dipaparkan dalam keputusan, dan parameter kedua ialah fungsi panggil balik yang mengandungi penegasan kami. Fungsi panggil balik ini dipanggil sebaik sahaja QUnit berjalan.
Kami menulis lima penegasan, yang kesemuanya adalah nilai boolean. Penegasan Boolean menjangkakan hujah pertamanya adalah benar. Parameter kedua juga merupakan mesej yang akan dipaparkan dalam keputusan.
Selepas menjalankan ujian, anda akan mendapat keputusan berikut:
由于所有这些断言都已成功通过,我们可以非常确定 isEven() 将按预期工作。
让我们看看如果断言失败会发生什么。
// Let's test this function function isEven(val) { return val % 2 === 0; } test('isEven()', function() { ok(isEven(0), 'Zero is an even number'); ok(isEven(2), 'So is two'); ok(isEven(-4), 'So is negative four'); ok(!isEven(1), 'One is not an even number'); ok(!isEven(-7), 'Neither does negative seven'); // Fails ok(isEven(3), 'Three is an even number'); })
结果如下:
断言失败是因为我们故意写错了,但在你自己的项目中,如果测试没有通过,并且所有断言都是正确的,你就知道发现了一个bug。
ok() 并不是 QUnit 提供的唯一断言。在测试项目时,还有其他类型的断言很有用:
比较断言 equals() 期望其第一个参数(即实际值)等于其第二个参数(即期望值)。它与 ok() 类似,但同时输出实际值和期望值,使调试更加容易。与 ok() 一样,它采用可选的第三个参数作为要显示的消息。
所以代替:
test('assertions', function() { ok( 1 == 1, 'one equals one'); })
你应该写:
test('assertions', function() { equals( 1, 1, 'one equals one'); })
注意最后一个“1”,这是比较值。
如果值不相等:
test('assertions', function() { equals( 2, 1, 'one equals one'); })
它提供了更多信息,使生活变得更加轻松。
比较断言使用“==”来比较其参数,因此它不处理数组或对象比较:
test('test', function() { equals( {}, {}, 'fails, these are different objects'); equals( {a: 1}, {a: 1} , 'fails'); equals( [], [], 'fails, there are different arrays'); equals( [1], [1], 'fails'); })
为了测试这种相等性,QUnit 提供了另一种断言:相同断言。
相同的断言,same(),需要与 equals() 相同的参数,但它是一个深度递归比较断言,不仅适用于基本类型,还适用于数组和对象。在前面的示例中,如果将断言更改为相同的断言,它们将全部通过:
test('test', function() { same( {}, {}, 'passes, objects have the same content'); same( {a: 1}, {a: 1} , 'passes'); same( [], [], 'passes, arrays have the same content'); same( [1], [1], 'passes'); })
请注意,same() 在可能的情况下使用“===”进行比较,因此在比较特殊值时它会派上用场:
test('test', function() { equals( 0, false, 'true'); same( 0, false, 'false'); equals( null, undefined, 'true'); same( null, undefined, 'false'); })
将所有断言放在一个测试用例中是一个非常糟糕的主意,因为它很难维护,并且不会返回干净的结果。您应该做的是构建它们,将它们放入不同的测试用例中,每个测试用例都针对单一功能。
您甚至可以通过调用模块函数将测试用例组织到不同的模块中:
module('Module A'); test('a test', function() {}); test('an another test', function() {}); module('Module B'); test('a test', function() {}); test('an another test', function() {});
在前面的示例中,所有断言都是同步调用的,这意味着它们依次运行。在现实世界中,还有很多异步函数,例如ajax调用或setTimeout()和setInterval()调用的函数。我们如何测试这些类型的功能? QUnit 提供了一种特殊的测试用例,称为“异步测试”,专门用于异步测试:
我们先尝试用常规的方式来写:
test('asynchronous test', function() { setTimeout(function() { ok(true); }, 100) })
看到了吗?就好像我们没有写任何断言一样。这是因为断言是异步运行的,当它被调用时,测试用例已经完成。
这是正确的版本:
test('asynchronous test', function() { // Pause the test first stop(); setTimeout(function() { ok(true); // After the assertion has been called, // continue the test start(); }, 100) })
在这里,我们使用 stop() 暂停测试用例,调用断言后,我们使用 start() 继续。
调用 test() 后立即调用 stop() 是很常见的;所以QUnit提供了一个快捷方式:asyncTest()。您可以像这样重写前面的示例:
asyncTest('asynchronous test', function() { // The test is automatically paused setTimeout(function() { ok(true); // After the assertion has been called, // continue the test start(); }, 100) })
有一点需要注意:setTimeout() 将始终调用其回调函数,但如果它是自定义函数(例如 ajax 调用)怎么办?您如何确定回调函数将被调用?如果不调用回调,则不会调用 start(),整个单元测试将挂起:
所以这就是你要做的:
// A custom function function ajax(successCallback) { $.ajax({ url: 'server.php', success: successCallback }); } test('asynchronous test', function() { // Pause the test, and fail it if start() isn't called after one second stop(1000); ajax(function() { // ...asynchronous assertions start(); }) })
您将超时传递给 stop(),它告诉 QUnit,“如果在该超时后未调用 start(),则该测试应该失败。”您可以确信整个测试不会挂起,并且如果出现问题您将会收到通知。
多个异步函数怎么样?你把start()放在哪里?你把它放在setTimeout()中:
// A custom function function ajax(successCallback) { $.ajax({ url: 'server.php', success: successCallback }); } test('asynchronous test', function() { // Pause the test stop(); ajax(function() { // ...asynchronous assertions }) ajax(function() { // ...asynchronous assertions }) setTimeout(function() { start(); }, 2000); })
超时应该足够长,以允许在测试继续之前调用两个回调。但是如果其中一个回调没有被调用怎么办?你怎么知道这一点?这就是expect() 发挥作用的地方:
// A custom function function ajax(successCallback) { $.ajax({ url: 'server.php', success: successCallback }); } test('asynchronous test', function() { // Pause the test stop(); // Tell QUnit that you expect three assertions to run expect(3); ajax(function() { ok(true); }) ajax(function() { ok(true); ok(true); }) setTimeout(function() { start(); }, 2000); })
你向expect()传递一个数字来告诉QUnit你期望运行X个断言,如果其中一个断言没有被调用,数字将不匹配,并且你会被通知有事情发生错了。
expect() 还有一个快捷方式:只需将数字作为第二个参数传递给 test() 或 asyncTest():
// A custom function function ajax(successCallback) { $.ajax({ url: 'server.php', success: successCallback }); } // Tell QUnit that you expect three assertion to run test('asynchronous test', 3, function() { // Pause the test stop(); ajax(function() { ok(true); }) ajax(function() { ok(true); ok(true); }) setTimeout(function() { start(); }, 2000); })
这就是开始使用 QUnit 所需了解的全部内容。单元测试是在发布代码之前测试代码的好方法。如果您之前没有编写过任何单元测试,那么现在就开始吧!感谢您的阅读!
Atas ialah kandungan terperinci Menguji kod JavaScript dengan QUnit: panduan langkah demi langkah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!