Podczas pisania narzędzia do uruchamiania testów należy pamiętać o skalowalności. Zadaj sobie pytanie: „Ile czasu zajęłoby uruchomienie 200 tys. przypadków testowych przez narzędzie do uruchamiania testów?”.
Dzielenie na partycje to jedna z odpowiedzi dostępnych w Trade Federation. Wymaga to podzielenia wszystkich testów, które ma wykonać narzędzie, na kilka części, które można uruchamiać równolegle.
Z tego artykułu dowiesz się, jak sprawić, aby moduł uruchamiający był dzielony na fragmenty w Tradefed.
Interfejs do wdrożenia
Najważniejszym interfejsem, który należy wdrożyć, aby TF uznał test za możliwy do podzielenia na fragmenty, jest IShardableTest, który zawiera 2 metody: split(int numShard) i split().
Jeśli podział na fragmenty ma zależeć od liczby żądanych fragmentów, musisz wdrożyć split(int numShard). W przeciwnym razie wdróż split().
Gdy polecenie testowe TF jest wykonywane z parametrami podziału --shard-count i --shard-index, TF iteruje wszystkie IRemoteTest, aby znaleźć te, które implementują IShardableTest. Jeśli zostanie znaleziony, wywoła funkcję split, aby uzyskać nowy obiekt IRemoteTest do uruchomienia podzbioru przypadków testowych dla określonego fragmentu.
Co muszę wiedzieć o wdrażaniu podzielonym?
- Aplikacja uruchamiająca może dzielić dane tylko pod pewnymi warunkami. W takim przypadku zwróć wartość
null, jeśli nie podzieliła danych. - Staraj się dzielić zadania tak, aby miało to sens: podziel runnera na jednostki wykonawcze, które mają dla niego sens. To zależy od biegacza. Na przykład: HostTest jest dzielony na poziomie klasy, a każda klasa testowa jest umieszczana w osobnym fragmencie.
- Jeśli to ma sens, dodaj kilka opcji, aby trochę kontrolować dzielenie.
Na przykład:AndroidJUnitTest
ma parametr
ajur-max-shard, który określa maksymalną liczbę fragmentów, na które można podzielić test, niezależnie od żądanej liczby.
Szczegółowy przykład implementacji
Oto przykładowy fragment kodu implementujący IShardableTest, z którego możesz skorzystać. Pełny kod jest dostępny pod adresem (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;
}
...
}
Ten przykład po prostu tworzy nową instancję samego siebie i ustawia dla niej parametry fragmentu. Logika podziału może się jednak różnić w zależności od testu. Ważne jest, aby była deterministyczna i tworzyła łącznie wyczerpujące podzbiory.
Independence
Fragmenty muszą być niezależne. Dwa fragmenty utworzone przez implementację split w programie uruchamiającym nie powinny być od siebie zależne ani współdzielić zasobów.
Podział fragmentów musi być deterministyczny. Jest to również obowiązkowe, ponieważ w tych samych warunkach metoda split powinna zawsze zwracać dokładnie tę samą listę fragmentów w tej samej kolejności.
UWAGA: ponieważ każdy fragment może działać na różnych instancjach TF, ważne jest, aby logika split generowała podzbiory, które są wzajemnie wykluczające się i łącznie wyczerpujące w deterministyczny sposób.
Dzielenie testu lokalnie
Aby podzielić test na partycje na lokalnym TF, wystarczy dodać opcję --shard-count do wiersza poleceń.
tf >run host --class com.android.tradefed.UnitTests --shard-count 3
Następnie TF automatycznie wygeneruje polecenia dla każdego fragmentu i je uruchomi.
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)
Agregacja wyników testów
TF nie agreguje wyników testów w przypadku wywołań podzielonych na fragmenty, więc musisz się upewnić, że Twoja usługa raportowania to obsługuje.