Как переопределить путь тестов Android с помощью Gradle?

По историческим причинам инструментальные тесты не хранятся в каталоге androidTests , как это требуется. и я не могу изменить структуру каталогов (на самом деле все приложение является тестом для используемой библиотеки). Мне удалось собрать и установить apk с помощью gradle, но тестов не найдено:

:app-tests:connectedDebugAndroidTest
Tests on test_avd(AVD) - 4.1.2 failed: Instrumentation run failed due to 'java.lang.ClassNotFoundException'

com.android.builder.testing.ConnectedDevice > No tests found.[test_avd(AVD) - 4.1.2] FAILED 
No tests found. This usually means that your test classes are not in the form that your test runner expects (e.g. don't inherit from TestCase or lack @Test annotations).
:app-tests:connectedDebugAndroidTest FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app-tests:connectedDebugAndroidTest'.
> There were failing tests. See the report at: file:///Users/asmirnov/Documents/dev/src/project/app-tests/build/reports/androidTests/connected/index.html

На самом деле тесты находятся в папке src, написаны правильно и могут быть собраны/запущены с помощью Ant:

public abstract class BaseTest extends AndroidTestCase
{
...

public class AppInfoTest extends BaseTest
{
    @Test
    public void testAllProperties()
    {
        ...

...

Как я могу заставить Gradle обрабатывать папку src как тесты Android (инструментальные)?

Вот мой текущий файл build.gradle (в нем используется экспериментальный плагин Android Gradle версия 0.7.2, потому что у нас есть библиотека NDK):

apply plugin: 'com.android.model.application'

allprojects {
    repositories {
        mavenLocal()
        mavenCentral()
    }
}

repositories {
    mavenLocal()
    mavenCentral()
}

model {
    android {
        compileSdkVersion 16
        buildToolsVersion "22.0.1"

        defaultConfig {
            applicationId "app.tests"
            minSdkVersion.apiLevel 9
            targetSdkVersion.apiLevel 16
            versionCode 359
            versionName "1.3"

            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }

        sources {
            main {
                // overriding paths from default ones to actual ones
                // what about 'androidTests' ?
                manifest { source {
                    srcDir '.'
                    include 'AndroidManifest.xml'
                } }
                java { source { srcDirs = ['src'] } }
                res { source { srcDirs = ['res'] } }
                jni {
                    dependencies {
                        project ":library" // native library dependency
                    }
                }
            }
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile project(':library')
}

ОБНОВЛЕНИЕ 1 (для sschuberth):

Конфигурация:

apply plugin: 'com.android.model.application'

allprojects {
    repositories {
        mavenLocal()
        mavenCentral()
    }
}

repositories {
    mavenLocal()
    mavenCentral()
}

model {
    android {
        compileSdkVersion 16
        buildToolsVersion "22.0.1"

        defaultConfig {
            applicationId "app.tests"
            minSdkVersion.apiLevel 9
            targetSdkVersion.apiLevel 16
            versionCode 359
            versionName "1.3"

            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }

        sourceSets {
            androidTest {
                manifest.srcFile 'AndroidManifest.xml' // error here
                java.srcDirs = ['src']
                res.srcDirs = ['res']
                assets.srcDirs = ['assets']
            }
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile project(':library')
}

Ошибка

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/asmirnov/Documents/dev/src/project/app-tests/build.gradle' line: 32

* What went wrong:
A problem occurred configuring project ':app-tests'.
> Exception thrown while executing model rule: android { ... } @ app-tests/build.gradle line 16, column 5
   > Could not find property 'manifest' on source set 'android test'.

person 4ntoine    schedule 10.08.2016    source источник


Ответы (3)


Не совсем уверен, что это сработает для вашего сценария, но вы можете обновить корень androidTest sourceSet следующим образом.

android {
    sourceSets {
        androidTest.setRoot('src')
    }
}

Существует также исходный набор test, если это просто код Java, ничего специфичного для Android.

Вы также можете поиграть с настройкой java.srcDir...

Приведенный выше параметр будет искать ваши файлы в этих местах.

<project>/<module>/src/AndroidManifest.xml
<project>/<module>/src/java

Если вы хотите переместить оба в каталог /src, вы можете использовать

sourceSets {
    androidTest {
        setRoot 'src'
        java.srcDirs = ['src']
    }
}

Дополнительные сведения об Android Gradle можно прочитать по адресу Настройка структуры


Вы можете отлаживать эти настройки самостоятельно с помощью этой настройки.

sourceSets {
    androidTest {
        setRoot 'src'
        java.srcDirs = ['./src']
    }

    println "androidTest.manifest.srcFile = ${androidTest.manifest.srcFile}"
    println "androidTest.java.srcDirs = ${androidTest.java.srcDirs}"
}

Когда вы просто очистите проект, вы увидите, что эти строки выводятся на консоль.

person OneCricketeer    schedule 10.08.2016
comment
> Could not find method manifest() for arguments [build_5blgy0rxz915fycj6huh3b3bg$_run_closure3$_closure6$_closure8$_closure9$_closure10@46935c97] on source set 'main'. возможно это из-за экспериментального плагина Gradle. Также я проверил, чтобы добавить его не в «основной» исходный набор, а в SourceSets, как в примере по ссылке. - person 4ntoine; 10.08.2016
comment
Не уверен, почему вы сообщаете мне об ошибке для чего-то, что существовало в вашем исходном коде. Я не показываю закрытие манифеста - person OneCricketeer; 10.08.2016
comment
Да, и, как я уже сказал, я не знаю о вашей ошибке, потому что она относится к настройке manifest, о которой я ничего не говорил. Вы можете проверить ссылку в моем ответе, чтобы узнать, как правильно идентифицировать файл манифеста для исходного набора. - person OneCricketeer; 10.08.2016
comment
я перешел по ссылке, но она не работает, как в примере - person 4ntoine; 10.08.2016
comment
да, для этого требуется манифест, поскольку тестовое приложение на самом деле является обычным приложением с инструментальным кодом. какую ошибку вы имеете в виду? - person 4ntoine; 10.08.2016
comment
Ошибка в вашем обновленном вопросе. Каталог test предназначен просто для тестового кода, такого как Mockito, JUnit и т. д. Инструментальный код, который вы тестируете, находится в main sourceSet, где находится манифест. - person OneCricketeer; 10.08.2016
comment
в обновленном вопросе нигде не указан каталог test: src используется для тестов Android: androidTest { java.srcDirs = ['src'] } - person 4ntoine; 10.08.2016
comment
Что именно мешает вам переместить тестовый код в рекомендуемую папку androidTests? - person OneCricketeer; 10.08.2016
comment
он настроен для сборки с помощью Ant и Maven, и я не могу что-то сломать, добавляя что-то. поэтому структура каталогов будет такой же - person 4ntoine; 10.08.2016
comment
Хорошо, тогда вы можете написать задачу Gradle для выполнения задач Ant/Maven вместо того, чтобы возиться с настройками местоположения Gradle. - person OneCricketeer; 10.08.2016
comment
ожидалось, что будет легко (задавать нестандартные пути), но это не так. Вы знаете, как это сделать? - person 4ntoine; 10.08.2016
comment
Лично мне никогда не приходилось изменять пути исходного набора Gradle по умолчанию. Ссылка, которую я предоставил в своем ответе, описывает настройки, которые вы бы использовали, если бы вы мигрировали из проекта Eclipse, где у вас было бы все в каталоге src/, как вы описываете. Я обновил свой ответ некоторыми дополнительными деталями - person OneCricketeer; 10.08.2016

Вместо sources {} вы должны использовать sourceSets {} и исходный набор androidTest для настройки расположения исходного кода теста:

model { // Required for experimental plugin.
    android {
        sourceSets {
            androidTest {
                manifest.srcFile '../AppTest/AndroidManifest.xml'
                java.srcDirs = ['../AppTest/src']
                res.srcDirs = ['../AppTest/res']
                assets.srcDirs = ['../AppTest/assets']
            }
        }
    }
}

Обратите внимание, что это не не относится к модульному тесту. Для модульного тестирования (например, с Robolectric) используйте исходный набор test.

person sschuberth    schedule 10.08.2016
comment
не работает: * What went wrong: A problem occurred configuring project ':app-tests'. > Exception thrown while executing model rule: android { ... } @ app-tests/build.gradle line 16, column 5 > Could not find method manifest() for arguments [build_5blgy0rxz915fycj6huh3b3bg$_run_closure3$_closure6$_closure8$_closure9$_closure10@a3d6b33] on source set 'android test'. Также обратите внимание, что синтаксис экспериментального плагина отличается от основного. - person 4ntoine; 10.08.2016
comment
Это не экспериментальный синтаксис плагина, я использую его с 2015 года. Также исходный набор должен называться androidTest, а не android test. - person sschuberth; 10.08.2016
comment
я использую экспериментальный плагин Gradle (0.7.2), и приведенный выше код НЕ работает для него - person 4ntoine; 10.08.2016
comment
Мне не хватало внешнего model закрытия. Я отредактировал свой ответ. - person sschuberth; 10.08.2016

Это было сложное решение: использовать экспериментальный плагин Gradle для компиляции нативного кода с помощью NDK и обычный плагин Gradle для тестового приложения.

построить.градле:

buildscript {
  repositories {
    mavenLocal()
    mavenCentral()
    jcenter()
  }
  dependencies {
    // experimental gradle plugin for the library to compile native code with NDK
    classpath "com.android.tools.build:gradle-experimental:0.7.2"

    // regular gradle plugin for the tests
    classpath 'com.android.tools.build:gradle:2.1.2'
  }
}

subprojects {
  task listAllDependencies(type: DependencyReportTask) {}
}

градация библиотеки (экспериментальная):

apply plugin: 'com.android.model.library'

...

model {

    android {
      ...
      ndk {
          moduleName = "library-jni"
          cppFlags.add("-std=c++11")
          cppFlags.add("-fexceptions")
          stl = "c++_static"

          abiFilters.addAll(['armeabi-v7a', 'x86']) // supported abis only
       }
       ...
    }
    ...
}

приложение/build.gradle (обычное):

apply plugin: 'com.android.application'

allprojects {
  repositories {
    mavenLocal()
    mavenCentral()
  }
}

repositories {
  mavenLocal()
  mavenCentral()
}

android {
  compileSdkVersion 16
  buildToolsVersion "22.0.1"

  defaultConfig {
    applicationId "app.tests"
    minSdkVersion 9
    targetSdkVersion 16
    versionCode 359
    versionName "1.3"

    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  }

  sourceSets {
    main {
      manifest.srcFile 'AndroidManifest.xml'
    }

    androidTest {
      manifest.srcFile 'AndroidManifest.xml'
      java.srcDirs = ['src']

      jni {
        dependencies {
          project ":library"
        }
      }
    }
  }
}

dependencies {
  androidTestCompile project(':library')
  androidTestCompile fileTree(include: ['*.jar'], dir: 'libs')
}
person 4ntoine    schedule 11.08.2016