編寫分割的 IRemoteTest 測試執行程式

編寫測試執行器時,請務必考慮擴充性。請自問:「如果測試執行器必須執行 20 萬個測試案例」,需要多少時間?

分片是 Trade Federation 中可用的答案之一。這需要將執行器需要的所有測試分割成多個可平行化的區塊。

本頁說明如何讓 Runner 可供 Tradefed 分片。

要實作的介面

如要讓 TF 視為可分片,最重要的介面就是 IShardableTest,其中包含 split(int numShard)split() 這兩種方法。

如果分片作業取決於要求的分片數量,您應實作 split(int numShard)。否則,請實作 split()

使用分片參數 --shard-count--shard-index 執行 TF 測試指令時,TF 會逐一檢查所有 IRemoteTest,找出實作 IShardableTest 的項目。如果找到,系統會呼叫 split 取得新的 IRemoteTest 物件,以便執行特定分片的測試案例子集。

有關分割導入,我應該瞭解哪些事項?

  • 只有在符合某些條件時,執行者才會分片;在這種情況下,如果沒有分片,請傳回 null
  • 盡量拆分,將執行器拆分成適合的執行單元。這取決於您的執行器。舉例來說: HostTest 會在類別層級分片,每個測試類別都會放在不同的分片中。
  • 如果合理,請新增一些選項來稍微控管分片。舉例來說: AndroidJUnitTest 具有 ajur-max-shard,可指定可分割的上限分片數,無論要求的分片數為何。

詳細的導入範例

以下是實作 IShardableTest 的程式碼片段範例,可供您參考。完整程式碼請參閱 (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/android16-release/test_framework/com/android/tradefed/testtype/InstalledInstrumentationsTest.java)

/**
 * Runs all instrumentation found on current device.
 */
@OptionClass(alias = "installed-instrumentation")
public class InstalledInstrumentationsTest
        implements IDeviceTest, IResumableTest, IShardableTest {
    ...

    /** {@inheritDoc} */
    @Override
    public Collection<IRemoteTest> split(int shardCountHint) {
        if (shardCountHint > 1) {
            Collection<IRemoteTest> shards = new ArrayList<>(shardCountHint);
            for (int index = 0; index < shardCountHint; index++) {
                shards.add(getTestShard(shardCountHint, index));
            }
            return shards;
        }
        // Nothing to shard
        return null;
    }

    private IRemoteTest getTestShard(int shardCount, int shardIndex) {
        InstalledInstrumentationsTest shard = new InstalledInstrumentationsTest();
        try {
            OptionCopier.copyOptions(this, shard);
        } catch (ConfigurationException e) {
            CLog.e("failed to copy instrumentation options: %s", e.getMessage());
        }
        shard.mShardIndex = shardIndex;
        shard.mTotalShards = shardCount;
        return shard;
    }
    ...
}

這個範例只會建立自己的新執行個體,並為其設定分片參數。不過,每次測試的分割邏輯可能完全不同;只要是確定性邏輯,且能產生全體詳盡的子集,就沒問題。

獨立

分片必須獨立!實作 split 時,在執行器中建立的兩個分片不應彼此有依附元件,也不應共用資源。

分片分割必須是決定性!在相同條件下,split 方法一律應傳回完全相同的分片清單,且順序相同,因此這也是必要條件。

注意:由於每個分片都可以在不同的 TF 執行個體上執行,因此請務必確保 split 邏輯會以決定性方式產生互斥且集體詳盡的子集。

在本機將測試分片

如要在本機 TF 上將測試分片,只要在指令列中加入 --shard-count 選項即可。

tf >run host --class com.android.tradefed.UnitTests --shard-count 3

接著,TF 會自動為每個分片產生指令並執行。

tf >l i
Command Id  Exec Time  Device          State
3           0m:03      [null-device-2]  running stub on build 0 (shard 1 of 3)
3           0m:03      [null-device-1]  running stub on build 0 (shard 0 of 3)
3           0m:03      [null-device-3]  running stub on build 0 (shard 2 of 3)

測試結果匯總

由於 TF 不會匯總分片呼叫的任何測試結果,因此請務必確認您的報表服務支援這項功能。