Kiểm thử đơn vị

Sau khi thay đổi hoặc thêm mã, bạn nên chạy các bài kiểm thử đơn vị hiện có và cân nhắc viết thêm. Tất cả các kiểm thử đều được thực thi trên phiên bản mã chưa nén.

Có hai tập hợp kiểm thử đơn vị: kiểm thử JS và kiểm thử trình tạo khối.

Kiểm thử JS

Các bài kiểm thử JS xác nhận hoạt động của các hàm JavaScript nội bộ trong lõi của Blockly. Chúng tôi sử dụng Mocha để chạy kiểm thử đơn vị, Sinon để chạy các phần phụ thuộc giả lập và Chai để đưa ra câu nhận định về mã này.

Chạy kiểm thử

Trong cả mẫu khối và mẫu khối, npm run test sẽ chạy các bài kiểm thử đơn vị. Trong khối này, thao tác này cũng sẽ chạy các chương trình kiểm thử khác như tìm lỗi mã nguồn (lint) và biên dịch. Bạn cũng có thể mở tests/mocha/index.html trong một trình duyệt để chạy tất cả các chương trình kiểm thử mocha theo cách tương tác.

Kiểm tra viết

Chúng tôi sử dụng giao diện Mocha TDD để chạy kiểm thử. Các bài kiểm thử được sắp xếp thành các bộ, có thể chứa cả các bộ con và/hoặc bài kiểm thử bổ sung. Nhìn chung, mỗi thành phần của Blockly (chẳng hạn như toolbox hoặc workspace) đều có tệp kiểm thử riêng chứa một hoặc nhiều bộ ứng dụng. Mỗi bộ có thể có một phương thức setupteardown. Phương thức này sẽ được gọi trước và sau tương ứng, mỗi kiểm thử trong bộ đó.

Trình trợ giúp thử nghiệm

Chúng tôi có một số chức năng trợ giúp dành riêng cho Blockly. Chức năng này có thể hữu ích khi viết kiểm thử. Bạn có thể tìm thấy các cấu hình này trong core (lõi) và trong blockly-samples (mẫu khối).

Các hàm trợ giúp bao gồm sharedTestSetupsharedTestTeardown bắt buộc phải được gọi trước và sau khi kiểm thử (xem phần Yêu cầu).

sharedTestSetup:
  • Thiết lập đồng hồ hẹn giờ giả sinon (trong một số kiểm thử, bạn sẽ cần sử dụng this.clock.runAll).
  • Blockly.Events.fire để kích hoạt ngay lập tức (có thể định cấu hình).
  • Thiết lập tính năng tự động xoá blockTypes đã xác định thông qua defineBlocksWithJsonArray.
  • Khai báo một số thuộc tính trên ngữ cảnh this mà bạn có thể truy cập:
    • this.clock (nhưng không nên được khôi phục, nếu không sẽ gây ra sự cố trong sharedTestTeardown)
    • this.eventsFireStub
    • this.sharedCleanup (để sử dụng với addMessageToCleanupaddBlockTypeToCleanup) (LƯU Ý: bạn không cần sử dụng addBlockTypeToCleanup nếu đã xác định khối bằng defineBlocksWithJsonArray)

Hàm này có một tham số options không bắt buộc để định cấu hình chế độ thiết lập. Hiện tại, thuộc tính này chỉ được dùng để xác định xem có cần mã giả lập Blockly.Events.fire kích hoạt ngay lập tức hay không (sẽ được mã hoá theo mặc định).

sharedTestTeardown:
  • Việc xử lý không gian làm việc this.workspace (tuỳ thuộc vào nơi được xác định, hãy xem phần Yêu cầu kiểm thử để biết thêm thông tin).
  • Khôi phục tất cả mã giả lập.
  • Xoá tất cả các loại khối được thêm vào thông qua defineBlocksWithJsonArrayaddBlockTypeToCleanup.
  • Xoá tất cả tin nhắn đã thêm qua addMessageToCleanup.

Yêu cầu kiểm thử

  • Mỗi lượt kiểm thử phải gọi sharedTestSetup.call(this); làm dòng đầu tiên trong quá trình thiết lập bộ ứng dụng ngoài cùng và sharedTestTeardown.call(this); là dòng cuối cùng trong phần phân tách của bộ ngoài cùng dành cho một tệp.
  • Nếu cần không gian làm việc có hộp công cụ chung, bạn có thể sử dụng một trong các hộp công cụ đặt lại trước trên index.html kiểm thử. Hãy xem ví dụ dưới đây.
  • Bạn phải vứt bỏ this.workspace đúng cách. Trong hầu hết kiểm thử, bạn sẽ xác định this.workspace trong bộ ngoài cùng và sử dụng cho tất cả các kiểm thử tiếp theo, nhưng trong một số trường hợp, bạn có thể xác định hoặc xác định lại trong một bộ kiểm thử bên trong (ví dụ: một trong các kiểm thử của bạn yêu cầu không gian làm việc có các tuỳ chọn khác với tuỳ chọn bạn đã thiết lập ban đầu). Bạn phải vứt bỏ thiết bị này khi kết thúc quá trình thử nghiệm.
    • Nếu đã định nghĩa this.workspace trong bộ ngoài cùng và không bao giờ xác định lại cấu trúc đó, thì bạn không cần làm gì thêm. sharedTestTeardown sẽ tự động bị huỷ bỏ.
    • Nếu lần đầu bạn xác định this.workspace trong một bộ bên trong (tức là bạn không xác định nó trong bộ ngoài cùng), bạn phải loại bỏ theo cách thủ công bằng cách gọi workspaceTeardown.call(this, this.workspace) trong phần phân tách của bộ đó.
    • Nếu bạn xác định this.workpace trong bộ ngoài cùng, nhưng sau đó xác định lại trong một bộ kiểm thử bên trong, trước tiên, bạn phải gọi workspaceTeardown.call(this, this.workspace) trước khi xác định lại để chia nhỏ không gian làm việc ban đầu được xác định trong bộ cấp cao nhất. Bạn cũng phải xử lý giá trị mới theo cách thủ công bằng cách gọi lại workspaceTeardown.call(this, this.workspace) trong quá trình chia nhỏ của bộ công cụ bên trong này.

Cấu trúc thử nghiệm

Các bài kiểm thử đơn vị thường tuân theo một cấu trúc cố định, có thể tóm tắt là sắp xếp, hành động, xác nhận.

  1. Arrange (Sắp xếp): Thiết lập trạng thái thế giới và mọi điều kiện cần thiết cho hành vi đang được kiểm thử.
  2. Hành động: Gọi mã đang được kiểm thử để kích hoạt hành vi đang được kiểm thử.
  3. Assert (Khẳng định): Đưa ra khẳng định về giá trị trả về hoặc hoạt động tương tác với đối tượng được mô phỏng để xác minh tính chính xác.

Trong một kiểm thử đơn giản, có thể không có bất kỳ hành vi nào cần sắp xếp, đồng thời các giai đoạn hành động và xác nhận có thể được kết hợp bằng cách chèn lệnh gọi đến mã đang được kiểm thử trong quá trình xác nhận. Đối với các trường hợp phức tạp hơn, quá trình kiểm thử sẽ dễ đọc hơn nếu bạn tuân theo 3 giai đoạn này.

Dưới đây là một tệp kiểm thử mẫu (được đơn giản hoá từ thực tế).

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');
    });
  });
});

Những điều cần lưu ý trong ví dụ này:

  • Một bộ có thể chứa các bộ khác có thêm phương thức setupteardown.
  • Mỗi bộ và thử nghiệm có một tên mang tính mô tả.
  • Câu nhận định Chai được dùng để xác nhận mã.
    • Bạn có thể cung cấp một đối số chuỗi không bắt buộc sẽ xuất hiện nếu quá trình kiểm thử không thành công. Điều này giúp bạn dễ dàng gỡ lỗi các lượt kiểm thử bị lỗi.
    • Thứ tự của các thông số là chai.assert.equal(actualValue, expectedValue, optionalMessage). Nếu bạn hoán đổi actualexpected, các thông báo lỗi sẽ không hợp lý.
  • Sinon được dùng để giả lập các phương thức khi bạn không muốn gọi mã thực. Trong ví dụ này, chúng tôi không muốn gọi hàm chỉ số thực vì nó không liên quan đến phép kiểm thử này. Chúng tôi chỉ quan tâm đến cách phương thức đang kiểm thử sử dụng kết quả. Sinon mã hoá hàm getMetrics để trả về một phản hồi soạn trước mà chúng ta có thể dễ dàng kiểm tra trong các câu nhận định kiểm thử.
  • Các phương thức setup cho mỗi bộ chỉ nên chứa chế độ thiết lập chung áp dụng cho tất cả chương trình kiểm thử. Nếu việc kiểm thử cho một hành vi cụ thể dựa vào một điều kiện nhất định, thì điều kiện đó phải được nêu rõ trong quy trình kiểm thử có liên quan.

Kiểm thử gỡ lỗi

  • Bạn có thể mở chương trình kiểm thử trong một trình duyệt và sử dụng công cụ cho nhà phát triển để đặt điểm ngắt và điều tra xem chương trình kiểm thử của bạn có đạt kết quả không như mong đợi hay không (hoặc đạt không như mong đợi!).
  • Đặt .only() hoặc .skip() trên một kiểm thử hoặc bộ công cụ để chỉ chạy kiểm thử đó hoặc bỏ qua một kiểm thử. Ví dụ:

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

    Hãy nhớ xoá các đối tượng này trước khi chuyển giao (commit) mã của bạn.

Kiểm tra trình tạo khối

Mỗi khối có các bài kiểm thử đơn vị riêng. Những hoạt động kiểm thử này xác minh rằng các khối tạo mã chứ không phải các hàm như dự định.

  1. Tải tests/generators/index.html trong Firefox hoặc Safari. Xin lưu ý rằng Chrome và Opera có các hạn chế về bảo mật ngăn chặn việc tải các bài kiểm thử từ hệ thống "file://" cục bộ (Vấn đề 4102447416).
  2. Chọn phần liên quan của hệ thống để kiểm thử trong trình đơn thả xuống rồi nhấp vào "Tải". Thao tác chặn sẽ xuất hiện trong không gian làm việc.
  3. Nhấp vào "JavaScript".
    Sao chép và chạy mã đã tạo trong bảng điều khiển JavaScript. Nếu kết quả kết thúc bằng "OK", thì tức là kiểm thử đã thành công.
  4. Nhấp vào "Python".
    Sao chép và chạy mã đã tạo trong trình thông dịch Python. Nếu kết quả kết thúc bằng "OK", thì có nghĩa là kiểm thử đã thành công.
  5. Nhấp vào "PHP".
    Sao chép và chạy mã đã tạo trong trình thông dịch PHP. Nếu kết quả kết thúc bằng "OK", thì có nghĩa là kiểm thử đã thành công.
  6. Nhấp vào "Lua".
    Sao chép và chạy mã đã tạo trong trình thông dịch Lua. Nếu kết quả kết thúc bằng "OK", thì có nghĩa là kiểm thử đã thành công.
  7. Nhấp vào "Dart".
    Sao chép và chạy mã đã tạo trong trình thông dịch DAO. Nếu kết quả kết thúc bằng "OK", thì có nghĩa là kiểm thử đã thành công.

Chỉnh sửa kiểm thử trình tạo khối

  1. Tải tests/generators/index.html trong trình duyệt.
  2. Chọn phần có liên quan của hệ thống từ trình đơn thả xuống và nhấp vào "Tải". Thao tác chặn sẽ xuất hiện trong không gian làm việc.
  3. Thực hiện bất kỳ thay đổi hoặc bổ sung nào đối với khối.
  4. Nhấp vào "XML".
  5. Sao chép XML đã tạo vào tệp thích hợp trong tests/generators/.