Pengujian Unit

Setelah mengubah atau menambahkan kode, Anda harus menjalankan pengujian unit yang ada dan mempertimbangkan untuk menulis lebih banyak lagi. Semua pengujian dijalankan pada versi kode yang tidak dikompresi.

Ada dua set pengujian unit: pengujian JS dan pengujian generator blok.

Pengujian JS

Pengujian JS mengonfirmasi pengoperasian fungsi JavaScript internal dalam inti Blockly. Kita menggunakan Mocha untuk menjalankan pengujian unit, Sinon untuk menghentikan dependensi, dan Chai untuk membuat pernyataan tentang kode.

Menjalankan Pengujian

Dalam contoh blockly dan blockly, npm run test akan menjalankan pengujian unit. Di blockly, tindakan ini juga akan menjalankan pengujian lain seperti analisis lint dan kompilasi. Anda juga dapat membuka tests/mocha/index.html di browser untuk menjalankan semua pengujian mocha secara interaktif.

Ujian Menulis

Kami menggunakan antarmuka TDD Mocha untuk menjalankan pengujian. Pengujian disusun ke dalam suite, yang dapat berisi sub-suite dan/atau pengujian tambahan. Umumnya, setiap komponen Blockly (seperti toolbox atau workspace) memiliki file pengujiannya sendiri yang berisi satu atau beberapa suite. Setiap suite dapat memiliki metode setup dan teardown yang akan dipanggil sebelum dan sesudah, masing-masing pengujian dalam suite tersebut.

Alat Bantu Tes

Kami memiliki sejumlah fungsi bantuan khusus untuk Blockly yang mungkin berguna saat menulis pengujian. Ini dapat ditemukan di inti dan di sampel blockly.

Fungsi bantuan mencakup sharedTestSetup dan sharedTestTeardown yang harus dipanggil sebelum dan setelah pengujian Anda (lihat bagian Persyaratan).

sharedTestSetup:
  • Siapkan timer palsu sinon (dalam beberapa pengujian, Anda harus menggunakan this.clock.runAll).
  • Stub Blockly.Events.fire akan langsung diaktifkan (dapat dikonfigurasi).
  • Menyiapkan pembersihan otomatis blockTypes yang ditentukan melalui defineBlocksWithJsonArray.
  • Mendeklarasikan beberapa properti pada konteks this yang dimaksudkan untuk diakses:
    • this.clock (tetapi tidak boleh dipulihkan, karena akan menyebabkan masalah pada sharedTestTeardown)
    • this.eventsFireStub
    • this.sharedCleanup (untuk digunakan dengan addMessageToCleanup dan addBlockTypeToCleanup) (CATATAN: Anda tidak perlu menggunakan addBlockTypeToCleanup jika Anda menentukan blok menggunakan defineBlocksWithJsonArray)

Fungsi ini memiliki satu parameter options opsional untuk mengonfigurasi penyiapan. Saat ini, metode ini hanya digunakan untuk menentukan apakah akan menghentikan Blockly.Events.fire agar langsung diaktifkan (secara default akan menjadi stub).

sharedTestTeardown:
  • Membuang ruang kerja this.workspace (bergantung pada tempatnya ditetapkan, lihat bagian Persyaratan Pengujian untuk informasi selengkapnya).
  • Memulihkan semua stub.
  • Membersihkan semua jenis blok yang ditambahkan melalui defineBlocksWithJsonArray dan addBlockTypeToCleanup.
  • Membersihkan semua pesan yang ditambahkan melalui addMessageToCleanup.

Persyaratan Pengujian

  • Setiap pengujian harus memanggil sharedTestSetup.call(this); sebagai baris pertama dalam penyiapan suite terluar dan sharedTestTeardown.call(this); sebagai baris terakhir dalam pembongkaran suite terluar untuk sebuah file.
  • Jika memerlukan ruang kerja dengan toolbox umum, Anda dapat menggunakan salah satu toolbox yang telah ditetapkan pada pengujian index.html. Lihat contoh di bawah.
  • Anda harus membuang this.workspace dengan benar. Dalam sebagian besar pengujian, Anda akan menentukan this.workspace pada suite terluar dan menggunakannya untuk semua pengujian selanjutnya, tetapi dalam beberapa kasus, Anda dapat menentukan atau menentukan ulang dalam suite dalam (misalnya, salah satu pengujian memerlukan ruang kerja dengan opsi yang berbeda dari yang Anda siapkan sebelumnya). Item harus dibuang di akhir pengujian.
    • Jika Anda menentukan this.workspace di suite terluar dan tidak pernah menentukannya ulang, Anda tidak perlu melakukan tindakan lebih lanjut. Aset tersebut akan otomatis dibuang oleh sharedTestTeardown.
    • Jika Anda menentukan this.workspace untuk pertama kalinya di suite dalam (artinya, Anda tidak menentukannya di suite terluar), Anda harus membuangnya secara manual dengan memanggil workspaceTeardown.call(this, this.workspace) dalam pembongkaran suite tersebut.
    • Jika Anda menentukan this.workpace di suite terluar, tetapi kemudian menentukannya ulang dalam rangkaian pengujian internal, Anda harus memanggil workspaceTeardown.call(this, this.workspace) terlebih dahulu sebelum mendefinisikan ulang untuk menghapus ruang kerja asli yang ditentukan pada suite level atas. Anda juga harus membuang nilai baru secara manual dengan memanggil workspaceTeardown.call(this, this.workspace) lagi dengan pemecahan rangkaian dalam ini.

Struktur Uji

Pengujian unit umumnya mengikuti struktur yang ditetapkan, yang dapat diringkas sebagai mengatur, bertindak, menyatakan.

  1. Arrange: Menyiapkan status dunia dan kondisi yang diperlukan untuk perilaku yang sedang diuji.
  2. Bertindak: Panggil kode yang sedang diuji untuk memicu perilaku yang sedang diuji.
  3. Assert: Buat pernyataan tentang nilai yang ditampilkan atau interaksi dengan objek tiruan untuk memverifikasi ketepatan.

Dalam pengujian sederhana, mungkin tidak ada perilaku yang harus diatur dan tahap tindakan dan pernyataan dapat digabungkan dengan menyisipkan panggilan ke kode yang sedang diuji dalam pernyataan. Untuk kasus yang lebih kompleks, pengujian akan lebih mudah dibaca jika Anda tetap menggunakan 3 tahap ini.

Berikut adalah contoh file pengujian (yang disederhanakan dari yang sebenarnya).

suite('Flyout', function() {
  setup(function() {
    sharedTestSetup.call(this);
    this.toolboxXml = document.getElementById('toolbox-simple');
    this.workspace = Blockly.inject('blocklyDiv',
        {
          toolbox: this.toolboxXml
        });
  });

  teardown(function() {
    sharedTestTeardown.call(this);
  });

  suite('simple flyout', function() {
    setup(function() {
      this.flyout = this.workspace.getFlyout();
    });
    test('y is always 0', function() {
      // Act and assert stages combined for simple test case
      chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
    });
    test('x is right of workspace if flyout at right', function() {
      // Arrange
      sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
        viewWidth: 100,
      });
      this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
      this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;

      // Act
      var x = this.flyout.getX();

      // Assert
      chai.assert.equal(x, 100, 'x is right of workspace');
    });
  });
});

Hal-hal yang perlu diperhatikan dari contoh ini:

  • Suite dapat berisi suite lain yang memiliki metode setup dan teardown tambahan.
  • Setiap suite dan pengujian memiliki nama deskriptif.
  • Pernyataan chai digunakan untuk membuat pernyataan tentang kode.
    • Anda dapat memberikan argumen string opsional yang akan ditampilkan jika pengujian gagal. Hal ini mempermudah proses debug pengujian yang rusak.
    • Urutan parameternya adalah chai.assert.equal(actualValue, expectedValue, optionalMessage). Jika Anda menukar actual dan expected, pesan error tidak akan dapat diterima.
  • Sinon digunakan untuk menghentikan metode ketika Anda tidak ingin memanggil kode yang sebenarnya. Dalam contoh ini, kita tidak ingin memanggil fungsi metrik sebenarnya karena tidak relevan dengan pengujian ini. Kita hanya memperhatikan bagaimana hasilnya digunakan oleh metode yang diuji. Sinon menghentikan fungsi getMetrics untuk menampilkan template pesan yang dapat dengan mudah kita periksa dalam pernyataan pengujian.
  • Metode setup untuk setiap suite hanya boleh berisi penyiapan generik yang berlaku untuk semua pengujian. Jika pengujian untuk perilaku tertentu bergantung pada kondisi tertentu, kondisi tersebut harus dinyatakan dengan jelas dalam pengujian yang relevan.

Pengujian Proses Debug

  • Anda dapat membuka pengujian di browser dan menggunakan alat developer untuk menetapkan titik henti sementara serta menyelidiki apakah pengujian Anda gagal secara tidak terduga (atau lulus secara tidak terduga).
  • Tetapkan .only() atau .skip() pada pengujian atau suite untuk hanya menjalankan serangkaian pengujian tersebut, atau melewati pengujian. Contoh:

    suite.only('Workspace', function () {
      suite('updateToolbox', function () {
        test('test name', function () {
          // ...
        });
        test.skip('test I don’t care about', function () {
          // ...
        });
      });
    });
    

    Ingatlah untuk menghapusnya sebelum menyimpan kode Anda.

Pengujian Generator Pemblokiran

Setiap blok memiliki pengujian unit sendiri. Pengujian ini memverifikasi bahwa blok tersebut menghasilkan kode daripada fungsi yang dimaksudkan.

  1. Muat tests/generators/index.html di Firefox atau Safari. Perlu diketahui bahwa Chrome dan Opera memiliki batasan keamanan yang mencegah pemuatan pengujian dari sistem "file://" lokal (Masalah 41024 dan 47416).
  2. Pilih bagian sistem yang relevan untuk diuji dari menu drop-down, lalu klik "Load". Blok akan muncul di ruang kerja.
  3. Klik "JavaScript".
    Salin dan jalankan kode yang dihasilkan di konsol JavaScript. Jika output diakhiri dengan "OK", berarti pengujian telah lulus.
  4. Klik "Python".
    Salin dan jalankan kode yang dihasilkan dalam penafsir Python. Jika output diakhiri dengan "Oke", pengujian telah lulus.
  5. Klik "PHP".
    Salin dan jalankan kode yang dihasilkan dalam penerjemah PHP. Jika output diakhiri dengan "Oke", pengujian telah lulus.
  6. Klik "Lua".
    Salin dan jalankan kode yang dihasilkan dalam penerjemah Lua. Jika output diakhiri dengan "Oke", pengujian telah lulus.
  7. Klik "Dart".
    Salin dan jalankan kode yang dihasilkan di penerjemah Dart. Jika output diakhiri dengan "Oke", pengujian telah lulus.

Mengedit Pengujian Generator Blok

  1. Muat tests/generators/index.html di browser.
  2. Pilih bagian sistem yang relevan dari menu drop-down, lalu klik "Load". Blok akan muncul di ruang kerja.
  3. Buat perubahan atau penambahan pada blok.
  4. Klik "XML".
  5. Salin XML yang dihasilkan ke dalam file yang sesuai di tests/generators/.