Pengujian Unit

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

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

Pengujian JS

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

Menjalankan Pengujian

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

Menulis Pengujian

Kita 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 masing-masing akan dipanggil sebelum dan sesudah, setiap pengujian dalam rangkaian tersebut.

Helper Pengujian

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

Fungsi helper mencakup sharedTestSetup dan sharedTestTeardown yang diperlukan untuk dipanggil sebelum dan sesudah pengujian (lihat bagian Persyaratan).

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

Fungsi ini memiliki satu parameter options opsional untuk mengonfigurasi penyiapan. Saat ini, hanya digunakan untuk menentukan apakah akan membuat stub Blockly.Events.fire untuk segera diaktifkan (akan membuat stub secara default).

sharedTestTeardown:
  • Menghapus ruang kerja this.workspace (bergantung pada tempatnya ditentukan, lihat bagian Persyaratan Pengujian untuk mengetahui informasi selengkapnya).
  • Memulihkan semua stub.
  • Membersihkan semua jenis blok yang ditambahkan melalui defineBlocksWithJsonArray dan addBlockTypeToCleanup.
  • Menghapus 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 penghapusan suite terluar untuk file.
  • Jika memerlukan ruang kerja dengan toolbox umum, Anda dapat menggunakan salah satu toolbox preset pada index.html pengujian. Lihat contoh di bawah.
  • Anda harus membuang this.workspace dengan benar. Pada sebagian besar pengujian, Anda akan menentukan this.workspace di suite terluar dan menggunakannya untuk semua pengujian berikutnya, tetapi dalam beberapa kasus, Anda mungkin menentukan atau menentukan ulang kode tersebut di rangkaian dalam (misalnya, salah satu pengujian Anda memerlukan ruang kerja dengan opsi yang berbeda dari yang awalnya Anda siapkan). Alat ini harus dibuang di akhir pengujian.
    • Jika Anda menentukan this.workspace di suite terluar dan tidak pernah menentukan ulang, Anda tidak perlu melakukan tindakan lebih lanjut. Data tersebut akan otomatis dihapus oleh sharedTestTeardown.
    • Jika Anda menentukan this.workspace untuk pertama kalinya di suite dalam (yaitu Anda tidak menentukannya di suite terluar), Anda harus membuangnya secara manual dengan memanggil workspaceTeardown.call(this, this.workspace) dalam penghapusan suite tersebut.
    • Jika Anda menentukan this.workpace di suite terluar, tetapi kemudian menentukannya ulang di suite pengujian dalam, Anda harus terlebih dahulu memanggil workspaceTeardown.call(this, this.workspace) sebelum menentukan ulang untuk menghilangkan ruang kerja asli yang ditentukan di suite tingkat atas. Anda juga harus membuang nilai baru secara manual dengan memanggil workspaceTeardown.call(this, this.workspace) lagi dalam penghapusan suite dalam ini.

Struktur Pengujian

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 kebenarannya.

Dalam pengujian sederhana, mungkin tidak ada perilaku yang perlu 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 mengikuti 3 tahap ini.

Berikut adalah contoh file pengujian (disederhanakan dari aslinya).

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 masuk akal.
  • Sinon digunakan untuk membuat stub metode saat Anda tidak ingin memanggil kode yang sebenarnya. Dalam contoh ini, kita tidak ingin memanggil fungsi metrik yang sebenarnya karena tidak relevan dengan pengujian ini. Kita hanya peduli dengan cara hasil digunakan oleh metode yang sedang diuji. Sinon membuat stub fungsi getMetrics untuk menampilkan respons standar yang dapat kita periksa dengan mudah dalam pernyataan pengujian.
  • Metode setup untuk setiap suite hanya boleh berisi penyiapan umum 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 dan menyelidiki apakah pengujian Anda gagal secara tidak terduga (atau lulus secara tidak terduga).
  • Tetapkan .only() atau .skip() pada pengujian atau rangkaian pengujian untuk hanya menjalankan kumpulan pengujian tersebut, atau lewati pengujian. Contoh:

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

    Jangan lupa untuk menghapusnya sebelum melakukan commit pada kode Anda.

Pengujian Pembuat Blok

Setiap blok memiliki pengujian unitnya sendiri. Pengujian ini memverifikasi bahwa blok menghasilkan kode daripada berfungsi sebagaimana mestinya.

  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 "Muat". Blok akan muncul di ruang kerja.
  3. Klik "JavaScript".
    Salin dan jalankan kode yang dihasilkan dalam konsol JavaScript. Jika output diakhiri dengan "OK", berarti pengujian telah lulus.
  4. Klik "Python".
    Salin dan jalankan kode yang dihasilkan di penafsir Python. Jika output diakhiri dengan "OK", pengujian telah lulus.
  5. Klik "PHP".
    Salin dan jalankan kode yang dihasilkan di penafsir PHP. Jika output diakhiri dengan "OK", pengujian telah lulus.
  6. Klik "Lua".
    Salin dan jalankan kode yang dihasilkan dalam penafsir Lua. Jika output diakhiri dengan "OK", pengujian telah lulus.
  7. Klik "Dart".
    Salin dan jalankan kode yang dihasilkan di interpreter Dart. Jika output diakhiri dengan "OK", 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 "Muat". Blok akan muncul di ruang kerja.
  3. Buat perubahan atau penambahan pada blok.
  4. Klik "XML".
  5. Salin XML yang dihasilkan ke file yang sesuai di tests/generators/.