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.