變更或新增程式碼後,您應執行現有的單元測試,並考慮編寫更多測試。所有測試都會在未壓縮的程式碼版本上執行。
有兩組單元測試:JS 測試和區塊產生器測試。
JS 測試
JS 測試會確認 Blockly 核心中的內部 JavaScript 函式運作情形。我們使用 Mocha 執行單元測試,使用 Sinon 模擬依附元件,並使用 Chai 對程式碼做出斷言。
執行測試
在 Blockly 和 Blockly 範例中,npm run test
會執行單元測試。在 Blockly 中,這也會執行其他測試,例如 linting 和編譯。您也可以在瀏覽器中開啟 tests/mocha/index.html
,以互動方式執行所有 Mocha 測試。
編寫測試
我們使用 Mocha TDD 介面執行測試。測試會歸入套件,套件可包含其他子套件和/或測試。一般來說,Blockly 的每個元件 (例如 toolbox
或 workspace
) 都有自己的測試檔案,其中包含一或多個套件。每個套件都可以有 setup
和 teardown
方法,分別在該套件中每項測試的前後呼叫。
測試輔助程式
我們提供許多 Blockly 專屬的輔助函式,這些函式在編寫測試時可能會很實用。您可以在 core 和 blockly-samples 中找到這些元素。
輔助函式包含 sharedTestSetup
和 sharedTestTeardown
,您必須在測試前後呼叫這些函式 (請參閱「需求條件」一節)。
sharedTestSetup
:
- 設定 Sinon 假計時器 (在某些測試中,您需要使用
this.clock.runAll
)。 - 模擬 Blockly.Events.fire 立即觸發 (可設定)。
- 設定自動清除透過
defineBlocksWithJsonArray
定義的 blockType。 - 在
this
上下文中宣告幾個可存取的屬性:this.clock
(但不應還原,否則會導致sharedTestTeardown
發生問題)this.eventsFireStub
this.sharedCleanup
(與addMessageToCleanup
和addBlockTypeToCleanup
搭配使用) (注意:如果您使用defineBlocksWithJsonArray
定義區塊,則不需要使用addBlockTypeToCleanup
)
這個函式有一個選用 options
參數,可用於設定設定。目前,它只用於判斷是否要立即觸發 Blockly.Events.fire
的虛設項目 (預設會觸發虛設項目)。
sharedTestTeardown
:
- 釋放工作區
this.workspace
(取決於定義位置,詳情請參閱「測試規定」一節)。 - 還原所有存根。
- 清除透過
defineBlocksWithJsonArray
和addBlockTypeToCleanup
新增的所有區塊類型。 - 清除透過
addMessageToCleanup
新增的所有訊息。
測試規定
- 每個測試都必須在最外層套件的設定中,以第一行呼叫
sharedTestSetup.call(this);
,並在檔案最外層套件的拆解中,以最後一行呼叫sharedTestTeardown.call(this);
。 - 如果您需要含有通用工具箱的工作區,可以使用測試
index.html
中的其中一個預設工具箱。請參考以下範例。 - 請務必妥善處理
this.workspace
。在大多數測試中,您會在最外層套件中定義this.workspace
,並在所有後續測試中使用,但在某些情況下,您可能會在內部套件中定義或重新定義this.workspace
(例如,某個測試需要使用與您原先設定不同的選項的專用工作區)。必須在測試結束時丟棄。- 如果您在最外層套件中定義
this.workspace
,且從未重新定義,則不必採取進一步行動。它會自動由sharedTestTeardown
處理。 - 如果您在內部套件中首次定義
this.workspace
(也就是未在最外層套件中定義),則必須在該套件的拆解作業中呼叫workspaceTeardown.call(this, this.workspace)
,才能手動處置。 - 如果您在最外層套件中定義
this.workpace
,但在內部測試套件中重新定義,則必須先呼叫workspaceTeardown.call(this, this.workspace)
,再重新定義,才能拆除在頂層套件中定義的原始工作區。您還必須在這個內部套件的拆解作業中再次呼叫workspaceTeardown.call(this, this.workspace)
,以手動處置新值。
- 如果您在最外層套件中定義
測試結構
單元測試通常會遵循固定結構,可概括為「排列、執行、斷言」。
- Arrange:設定世界的狀態和測試行為的任何必要條件。
- 動作:呼叫測試中的程式碼,觸發要測試的行為。
- Assert:針對傳回值或與模擬物件互動的方式進行斷言,以便驗證正確性。
在簡單的測試中,可能沒有任何要安排的行為,您可以透過在斷言中內嵌對測試中程式碼的呼叫,將動作和斷言階段合併。對於較複雜的情況,如果您遵循這 3 個階段,測試的易讀性就會提高。
以下是測試檔案範例 (經過實際操作簡化)。
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');
});
});
});
本範例的注意事項:
- 套件可包含其他具有額外
setup
和teardown
方法的套件。 - 每個套件和測試都有描述性名稱。
- Chai 斷言可用於對程式碼做出斷言。
- 您可以提供選用的字串引數,在測試失敗時顯示該字串。這樣就能更輕鬆地偵錯失敗的測試。
- 參數的順序為
chai.assert.equal(actualValue, expectedValue, optionalMessage)
。如果您交換actual
和expected
,錯誤訊息就會變得毫無意義。
- 當您不想呼叫實際程式碼時,可以使用 Sinon 建立方法的存根。在這個範例中,我們不想呼叫實際的評估指標函式,因為這與此測試無關。我們只關注受測試方法如何使用結果。Sinon 會為
getMetrics
函式傳回虛設常式,以便傳回罐頭回應,方便在測試斷言中檢查。 - 每個套件的
setup
方法只能包含適用於所有測試的一般設定。如果針對特定行為的測試需要特定條件,則應在相關測試中明確指出該條件。
偵錯測試
- 您可以在瀏覽器中開啟測試,並使用開發人員工具設定中斷點,調查測試是否會發生非預期的失敗 (或意外通過) 情形。
在測試或套件上設定
.only()
或.skip()
,即可只執行該組測試,或略過測試。例如:suite.only('Workspace', function () { suite('updateToolbox', function () { test('test name', function () { // ... }); test.skip('test I don’t care about', function () { // ... }); }); });
請記得在提交程式碼前移除這些內容。
區塊產生器測試
每個區塊都有專屬的單元測試。這些測試會驗證區塊產生的程式碼是否超出預期。
- 在 Firefox 或 Safari 中載入
tests/generators/index.html
。請注意,Chrome 和 Opera 設有安全限制,禁止從本機「file://」系統載入測試 (問題 41024 和 47416)。 - 從下拉式選單中選取要測試的系統部分,然後按一下「Load」。區塊應會顯示在工作區中。
- 按一下「JavaScript」。
在 JavaScript 控制台中複製並執行產生的程式碼。如果輸出內容的結尾是「OK」,表示測試已通過。 - 按一下「Python」。
在 Python 解譯器中複製並執行產生的程式碼。如果輸出內容的結尾是「OK」,表示測試已通過。 - 按一下「PHP」。
複製並在 PHP 解譯器中執行產生的程式碼。如果輸出內容結尾為「OK」,表示測試已通過。 - 按一下「Lua」。
在 Lua 解譯器中複製並執行產生的程式碼。 如果輸出內容結尾為「OK」,表示測試已通過。 - 按一下「Dart」。
複製並在 Dart 解譯器中執行產生的程式碼。如果輸出內容的結尾是「OK」,表示測試已通過。
編輯區塊產生器測試
- 在瀏覽器中載入
tests/generators/index.html
。 - 從下拉式選單中選擇系統的相關部分,然後按一下「Load」。工作區應會顯示區塊。
- 對區塊進行任何變更或新增。
- 按一下「XML」。
- 將產生的 XML 複製到
tests/generators/
中的適當檔案。