Kiểm thử đơn vị

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

Có hai bộ 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 cốt lõi. Chúng ta sử dụng Mocha để chạy kiểm thử đơn vị, Sinon để tạo phần phụ thuộc mô phỏng và Chai để đưa ra xác nhận về mã.

Chạy kiểm thử

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

Kiểm thử việc viết

Chúng tôi sử dụng giao diện TDD Mocha để 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ả bộ phụ và/hoặc 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ộ kiểm thử. Mỗi bộ có thể có một phương thức setupteardown sẽ được gọi trước và sau mỗi lần kiểm thử trong bộ đó.

Trình trợ giúp kiểm thử

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

Các hàm trợ giúp bao gồm sharedTestSetupsharedTestTeardown là các hàm 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 bộ hẹn giờ giả của sinon (trong một số kiểm thử, bạn sẽ cần sử dụng this.clock.runAll).
  • Stubs 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á các blockTypes đã xác định defineBlocksWithJsonArray.
  • Khai báo một số thuộc tính trong ngữ cảnh this có thể truy cập:
    • this.clock (nhưng không được khôi phục nếu không sẽ gây ra sự cố trong sharedTestTeardown)
    • this.eventsFireStub
    • this.sharedCleanup (dùng với addMessageToCleanupaddBlockTypeToCleanup) (LƯU Ý: bạn không cần sử dụng addBlockTypeToCleanup nếu bạn đã xác định khối bằng cách sử dụ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, nó chỉ được dùng để xác định xem có cần giả lập Blockly.Events.fire để kích hoạt hay không ngay lập tức (sẽ là mã thay thế theo mặc định).

sharedTestTeardown:
  • Loại bỏ không gian làm việc this.workspace (tuỳ thuộc vào vị trí không gian làm việc đượ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ả các phần giữ chỗ.
  • Dọn dẹp mọi loại khối được thêm thông qua defineBlocksWithJsonArrayaddBlockTypeToCleanup.
  • Dọn dẹp tất cả thư đã thêm thông qua addMessageToCleanup.

Yêu cầu kiểm thử

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

Cấu trúc kiểm thử

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

  1. 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 đượ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. Xác nhận: Đưa ra khẳng định về giá trị trả về hoặc các lượt tương tác với để xác minh tính chính xác.

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

Dưới đây là một tệp thử nghiệm 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ó các phương thức setupteardown bổ sung.
  • Mỗi bộ và kiểm thử đều có tên mô tả.
  • Câu nhận định Chai được dùng để đưa ra câu nhận định về mã.
    • Bạn có thể cung cấp một đối số chuỗi không bắt buộc. Đối số này sẽ được hiển thị nếu kiểm thử không thành công. Thao tác này giúp bạn dễ dàng gỡ lỗi cho các chương trình kiểm thử bị hỏng.
    • Thứ tự của các tham 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 có ý nghĩa.
  • Sinon được dùng để tạo phương thức giả lập khi bạn không muốn gọi mã thực. Trong ví dụ này, chúng ta không muốn gọi hàm chỉ số thực vì hàm này không liên quan đến kiểm thử này. Chúng ta chỉ quan tâm đến cách phương thức đang kiểm thử sử dụng kết quả. Sinon dùng mã giả lập hàm getMetrics để trả về một mà chúng ta có thể dễ dàng kiểm tra trong 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ả các thử nghiệm. Nếu một kiểm thử cho một hành vi cụ thể dựa trên một điều kiện nhất định, thì điều kiện đó phải được nêu rõ trong kiểm thử liên quan.

Gỡ lỗi kiểm thử

  • Bạn có thể mở bài kiểm thử trong một trình duyệt rồi dùng công cụ cho nhà phát triển để thiết lập điểm ngắt và điều tra xem chương trình kiểm thử của bạn có thất bại ngoài dự kiến hay không (hoặc trôi qua bất ngờ!).
  • Đặt .only() hoặc .skip() trên một kiểm thử hoặc bộ kiểm thử để chỉ chạy tập hợp kiểm thử đó, hoặc bỏ qua một thử nghiệm. 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 mã này trước khi chuyển giao (commit) mã.

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

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

  1. Tải tests/generators/index.html trong Firefox hoặc Safari. Xin lưu ý rằng Chrome và Opera có các quy định hạn chế về bảo mật ngăn việc tải các chương trình kiểm thử từ hệ thống "file://" cục bộ (Vấn đề 4102447416).
  2. Chọn phần phù hợp của hệ thống để kiểm thử từ trình đơn thả xuống và nhấp vào "Tải". Các quy 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ã được tạo trong bảng điều khiển JavaScript. Nếu dữ liệu đầu ra kết thúc bằng "OK", nghĩa là kiểm tra đã 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ì kiểm thử đã đạt.
  5. Nhấp vào "PHP".
    Sao chép và chạy mã đã tạo trong trình phiên dịch PHP. Nếu kết quả kết thúc bằng "OK", tức 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 phiên dịch Lua. Nếu kết quả kết thúc bằng "OK", thì kiểm thử đã đạt.
  7. Nhấp vào "Dart".
    Sao chép và chạy mã đã tạo trong trình thông dịch Dart. Nếu kết quả kết thúc bằng "OK", tức là kiểm thử đã thành công.

Chỉnh sửa kiểm tra 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 rồi nhấp vào "Tải". Các quy tắc chặn sẽ xuất hiện trong không gian làm việc.
  3. Thực hiện mọi thay đổi hoặc bổ sung đối với các khối.
  4. Nhấp vào "XML".
  5. Sao chép tệp XML đã tạo vào tệp thích hợp trong tests/generators/.