Изолирующий тест APK build - PullRequest
0 голосов
/ 09 июля 2019

У меня есть ситуация, когда в проекте Android с инструментальными тестами весь рабочий код предварительно скомпилирован и готов к установке в виде .apk (среда React Native).

Всякий раз, когда я запускаю инструментарийВ тестах я изначально собираю AndroidTest .apk, используя Gradle, запустив:

./gradlew assembleDebugAndroidTest -DtestBuildType=debug

(т.е. довольно стандартным способом).

Проблема в том, что, несмотря на явное указание только xxxAndroidTestзадача, все рабочие задачи сборки кода Gradle задачи также выполняются.Для меня это огромная трата времени, поскольку, как я объяснил, производство apk уже существует, и поэтому компиляция кода (и упаковка, подписывание и т. Д.) Недостаточна.

По сути, у меня естьв рабочем коде нет зависимости от кода инструментария - даже используемый мной ActivityTestRule создается динамически и не связан напрямую с моей основной активностью:

Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(launchIntent, 0);
Class<?> activityClass = Class.forName(resolveInfo.activityInfo.name);
ActivityTestRule<?> activityTestRule = new ActivityTestRule(activityClass, false, false);

Вопрос заключается в следующем:Как я могу изолировать / ограничить работу Gradle, чтобы она включала только задачи, связанные с тестированием?Я даже попытался осмотреть дерево задач с помощью этого плагина Gradle , но не смог найти четкого места для «вырубки дерева».

1 Ответ

0 голосов
/ 10 июля 2019

Ну, до сих пор я придумал это (эвристическое) решение, которое делает 2 вещи:

  1. Я заметил, что большую часть времени тратится впустую из-за подпроектов, которые не нужны для работы. Таким образом, решение обеспечивает простой способ исключить implementation s из test building.

  2. Из задач, оставшихся в списке, по-прежнему - плагин итеративно отключает задачи, которые не связаны, но, тем не менее, выполняются.

Это сводится к этому вспомогательному скрипту Gradle:

// turbo-test-apk.gradle

def isEnabled = System.getProperty('TURBO_TEST_APK') != null

project.ext.dependenciesExcludeTest = { depsClosure ->
    if (!isEnabled) {
        dependencies(depsClosure)
    }
}

gradle.taskGraph.whenReady { graph ->
    if (isEnabled) {
        def disabledTasks = new ArrayList<Task>(graph.allTasks.size())

        [/.*JsAndAssets.*/, /package.*Release/, /package.*Debug/, /compile.*/, /.*[Pp]roguard.*/, /.*[Nn]ew[Rr]elic.*/, /.*AndroidTest.*/].forEach { regex ->
            graph.allTasks.findAll { it.name ==~ regex }.forEach({ task ->
                disabledTasks.add(task)
                task.enabled = false
            })
        }

        graph.allTasks.findAll { it.name ==~ /.*AndroidTest.*/ }.forEach({ task ->
            task.enabled = true
        })

        println '--- Turbo test build: task scanning ---'
        disabledTasks.forEach { task ->
            if (!task.enabled) {
                println 'Force-skipping ' + task
            }
        }
        println '---------------------------------------'
    }
}

А именно, dependenciesExcludeTest включил исключение нежелательных подпроектов, а обратный вызов, готовый к графу задач, отключает. ОБРАТИТЕ ВНИМАНИЕ, что список регулярных выражений сделан на заказ и не является общим . Это имеет смысл для моего проекта, так как на нативных проектах есть тяжелые задачи JS-связывания под названием bundleJsAndAssets, и у меня также установлена ​​новая реликвия. Тем не менее, это может быть легко адаптировано к любому проекту.

Кроме того, app.gradle выглядит примерно так:

apply plugin: 'com.android.application'

apply from: './turbo-test-apk.gradle'

dependencies {
    implementation "org.jetbrains.kotlin:$kotlin_stdlib:$kotlinVersion"
    implementation "com.android.support:support-v4:$supportLibraryVersion"
    implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
    // etc.
}
// These will be excluded when executing test-only mode
dependenciesExcludeTest {
    implementation project(':@react-native-community_async-storage')
    implementation project(':any-unneeded-sub-project')
}

Поэтому, когда gradle запускается так (т. Е. С пользовательским свойством TURBO_TEST_APK):

./gradlew assembleDebugAndroidTest -DtestBuildType=debug -DTURBO_TEST_APK

скрипт применит свою работу и сократит общее время сборки.

Это решение не оптимально: сложно обслуживать, не пропускает все ненужной работы. Я был бы очень рад увидеть более эффективные решения.

...