撰寫和執行測試 - MRTK2

為了確保 MRTK 可靠,MRTK 具有一組測試,以確保程式碼的變更不會回歸現有的行為。 在 MRTK 之類的大型程式碼基底中擁有良好的測試涵蓋範圍對於穩定性和在進行變更時具有信心非常重要。

MRTK 使用 Unity 測試執行器 ,其使用 NUnit的 Unity 整合。 本指南將提供如何將測試新增至 MRTK 的起點。 它不會說明 Unity 測試執行器和NUnit ,您可以在提供的連結中查閱。

提交提取要求之前,請務必:

  1. 在本機執行測試,讓變更不會在完成 PR (傳回現有的行為,如果有任何測試失敗) ,則不允許這麼做。

  2. 如果修正錯誤,請撰寫測試來測試修正,並確保未來的程式碼修改不會再次中斷。

  3. 如果撰寫功能,請撰寫新的測試,以防止即將發生的程式碼變更中斷此功能。

目前 Playmode 測試是要在 Unity 2018.4 中執行,而且在其他版本的 Unity 中可能會失敗

執行測試

Unity 編輯器

Unity 測試執行器可以在[視窗>一般>測試執行器] 下找到,並顯示所有可用的 MRTK 播放和編輯模式測試。

命令列

測試也可以由位於 Scripts\test\run_playmode_tests.ps1Powershell腳本執行。 這會執行 playmode 測試,就像在 github / CI 上執行一樣, (請參閱下列) 和列印結果。 以下是如何執行腳本的一些範例

在位於 H:\mrtk.dev 的專案上執行測試,Unity 2018.4 (例如 Unity 2018.4.26f1)

.\run_playmode_tests.ps1 H:\mrtk.dev -unityExePath "C:\Program Files\Unity\Hub\Editor\2018.4.26f1\Editor\Unity.exe"

在位於 H:\mrtk.dev 的專案上執行測試,使用 Unity 2018.4 將結果輸出至 C:\playmode_test_out

.\run_playmode_tests.ps1 H:\mrtk.dev -unityExePath "C:\Program Files\Unity\Hub\Editor\2018.4.26f1\Editor\Unity.exe" -outFolder "C:\playmode_test_out\"

您也可以透過 run_repeat_tests.ps1 腳本多次執行 Playmode 測試。 可以使用 中使用的 run_playmode_tests.ps1 所有參數。

.\run_repeat_tests.ps1 -Times 5

提取要求驗證

MRTK 的 CI 將會在所有設定中建置 MRTK,並執行所有編輯和播放模式測試。 如果使用者有足夠的許可權,可以在 github PR /azp run mrtk_pr 上張貼批註來觸發 CI。 CI 執行可以在 PR 的 [檢查] 索引標籤中看到。

只有在所有測試都成功通過之後,才能將 PR 合併到 main。

壓力測試/大量測試

有時候,測試偶爾只會失敗,這可能會令人感到無法偵錯。

若要在本機執行多個測試,請修改根據測試腳本。 下列 Python 腳本應該讓此案例更方便。

執行 Python 腳本的必要條件是 已安裝 Python 3.X

針對需要多次執行的單一測試:

[UnityTest]
public IEnumerator MyTest() {...}

建議從命令列執行下列命令, (PowerShell)

cd scripts\tests
# Repeat the test 5 times. Default is 100
python .\generate_repeat_tests.py -n 5 -t MyTest

將輸出複製並貼到測試檔案中。 下列腳本是依序執行多個測試:

cd scripts\tests
# Repeat the test 5 times. Default is 100
python .\generate_repeat_tests.py -n 5 -t MyTest MySecondTest

新的測試檔案現在應該包含

[UnityTest]
public IEnumerator A1MyTest0(){ yield return MyTest();}
[UnityTest]
public IEnumerator A2MyTest0(){ yield return MyTest();}
[UnityTest]
public IEnumerator A3MyTest0(){ yield return MyTest();}
[UnityTest]
public IEnumerator A4MyTest0(){ yield return MyTest();}
[UnityTest]
public IEnumerator MyTest() {...}

開啟測試執行器,並觀察現在可以重複呼叫的新測試。

編寫測試

有兩種類型的測試可以針對新程式碼新增

  • 播放模式測試
  • 編輯模式測試

播放模式測試

MRTK 播放模式測試能夠測試新功能如何回應不同的輸入來源,例如手部或眼睛。

新的播放模式測試可以繼承 BasePlayModeTests ,或可以使用下列基本架構。

若要建立新的播放模式測試:

  • 流覽至 > 資產 MRTK > 測試 > PlayModeTests
  • 以滑鼠右鍵按一下 [建立 > 測試 > C# 測試腳本]
  • 以下列基本架構取代預設範本
#if !WINDOWS_UWP
// When the .NET scripting backend is enabled and C# projects are built
// The assembly that this file is part of is still built for the player,
// even though the assembly itself is marked as a test assembly (this is not
// expected because test assemblies should not be included in player builds).
// Because the .NET backend is deprecated in 2018 and removed in 2019 and this
// issue will likely persist for 2018, this issue is worked around by wrapping all
// play mode tests in this check.

using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities;
using NUnit.Framework;
using System;
using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEngine.TestTools;

namespace Microsoft.MixedReality.Toolkit.Tests
{
    class ExamplePlayModeTests
    {
        // This method is called once before we enter play mode and execute any of the tests
        // do any kind of setup here that can't be done in playmode
        public void Setup()
        {
            // eg installing unity packages is only possible in edit mode
            // so if a test requires TextMeshPro we will need to check for the package before entering play mode
            PlayModeTestUtilities.InstallTextMeshProEssentials();
        }

        // Do common setup for each of your tests here - this will be called for each individual test after entering playmode
        // Note that this uses UnitySetUp instead of [SetUp] because the init function needs to await a frame passing
        // to ensure that the MRTK system has had the chance to fully set up before the test runs.
        [UnitySetUp]
        public IEnumerator Init()
        {
            // in most play mode test cases you would want to at least create an MRTK GameObject using the default profile
            TestUtilities.InitializeMixedRealityToolkit(true);
            yield return null;
        }

        // Destroy the scene - this method is called after each test listed below has completed
        // Note that this uses UnityTearDown instead of [TearDown] because the init function needs to await a frame passing
        // to ensure that the MRTK system has fully torn down before the next test setup->run cycle starts.
        [UnityTearDown]
        public IEnumerator TearDown()
        {
            PlayModeTestUtilities.TearDown();
            yield return null;
        }

        #region Tests

        /// <summary>
        /// Skeleton for a new MRTK play mode test.
        /// </summary>
        [UnityTest]
        public IEnumerator TestMyFeature()
        {
            // ----------------------------------------------------------
            // EXAMPLE PLAY MODE TEST METHODS
            // ----------------------------------------------------------
            // Getting the input system
            // var inputSystem = PlayModeTestUtilities.GetInputSystem();

            // Creating a new test hand for input
            // var rightHand = new TestHand(Handedness.Right);
            // yield return rightHand.Show(new Vector3(0, 0, 0.5f));

            // Moving the new test hand
            // We are doing a yield return here because moving the hand to a new position
            // requires multiple frames to complete the action.
            // yield return rightHand.MoveTo(new Vector3(0, 0, 2.0f));

            // Getting a specific pointer from the hand
            // var linePointer = PointerUtils.GetPointer<LinePointer>(Handedness.Right);
            // Assert.IsNotNull(linePointer);
            // ---------------------------------------------------------

            // Your new test here
            yield return null;
        }
        #endregion
    }
}
#endif

編輯模式測試

編輯模式測試是在 Unity 的編輯模式中執行,而且可以在 Mixed Reality Toolkit 存放庫中的MRTK>測試>EditModeTests資料夾下新增。 若要建立新的測試,可以使用下列範本:

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using NUnit.Framework;

namespace Microsoft.MixedReality.Toolkit.Tests
{
    class EditModeExampleTest
    {
        [Test]
        /// the name of this method will be used as test name in the unity test runner
        public void TestEditModeExampleFeature()
        {

        }
    }
}

測試命名慣例

測試通常應該根據其正在測試的類別,或測試的案例來命名。 例如,假設有待測試的類別:

namespace Microsoft.MixedReality.Toolkit.Input
{
    class InterestingInputClass
    {
    }
}

請考慮命名測試

namespace Microsoft.MixedReality.Toolkit.Tests.Input
{
    class InterestingInputClassTest
    {
    }
}

請考慮將測試放在與對應之非測試檔案類似的資料夾階層中。 例如:

Non-Test: Assets/MRTK/Core/Utilities/InterestingUtilityClass.cs
Test: Assets/MRTK/Tests/EditModeTests/Core/Utilities/InterestingUtilityClassTest.cs

這是為了確保在這類測試類別存在時,找出每個類別對應測試類別的明顯方式。

案例型測試的位置較不定義 - 如果測試練習整體輸入系統,例如,請考慮將它放入對應的編輯模式或播放模式測試檔案夾中的 「InputSystem」 資料夾。

測試腳本圖示

新增測試時,請修改腳本以擁有正確的 MRTK 圖示。 有一個簡單的 MRTK 工具可以這麼做:

  1. 移至 [Mixed Reality工具組] 功能表項目
  2. 按一下 [公用程式],然後按一下 [更新],然後按一下 [圖示]
  3. 按一下 [測試],更新程式會自動執行,並更新遺漏其圖示的任何測試腳本

MRTK 公用程式方法

本節說明撰寫 MRTK 測試時的一些常用程式碼片段/方法。

有兩個公用程式類別可協助設定 MRTK,以及測試與 MRTK 中的元件互動

TestUtilities 提供下列方法來設定 MRTK 場景和 GameObjects:

/// creates the mrtk GameObject and sets the default profile if passed param is true
TestUtilities.InitializeMixedRealityToolkit()

/// creates an empty scene prior to adding the mrtk GameObject to it
TestUtilities.InitializeMixedRealityToolkitAndCreateScenes();

/// sets the initial playspace transform and camera position
TestUtilities.InitializePlayspace();

/// destroys previously created mrtk GameObject and playspace
TestUtilities.ShutdownMixedRealityToolkit();

請參閱 和 PlayModeTestUtilities 的 API 檔 TestUtilities ,以取得這些 util 類別的進一步方法,因為它們會定期擴充,而新的測試會新增至 MRTK。