问题
我想创建一个自定义gradle测试任务,只运行JUNIT测试并省略Robolectric测试。我试图通过创建一个新的测试注释并省略包含该新注释的任何测试来完成此任务。
错误
运行gradle任务时不包括JUNIT包。
error: package android.test.suitebuilder.annotation does not exist
import android.test.suitebuilder.annotation.SmallTest;
详情
新注释
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RobolectricTest {
}
Gradle文件
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
repositories {
mavenCentral()
maven { url 'http://artifactory.ops.am1.qa.ext.bamgrid.com/artifactory/mobile-resources' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.google.gms:google-services:1.3.0-beta1'
}
}
android {
compileSdkVersion rootProject.ext.compileSDKVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.example"
minSdkVersion 17
targetSdkVersion rootProject.ext.targetSdkVersion
buildConfigField "String", "BUILD_TIME", "\"" + getDateAndTime() + "\""
buildConfigField "String", "VERSION_BUILD", "\"" + project["VERSION_BUILD"] + "\""
versionCode Integer.parseInt(project.VERSION_CODE)
versionName project.VERSION_NAME
}
signingConfigs {
debug {
storeFile file(project.DEBUG_KEYSTORE)
storePassword project.DEBUG_KEYSTORE_PASSWORD
keyAlias project.DEBUG_KEYSTORE_ALIAS
keyPassword project.DEBUG_KEY_PASS
}
release {
storeFile file(project.RELEASE_KEYSTORE)
storePassword project.RELEASE_KEYSTORE_PASSWORD
keyAlias project.RELEASE_KEYSTORE_ALIAS
keyPassword project.RELEASE_KEY_PASS
}
}
sourceSets {
main {
res.srcDirs = ['src/main/res/',
'src/main/abc']
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
proguardFile 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
testCoverageEnabled = true
debuggable true
signingConfig signingConfigs.debug
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile ('junit:junit:4.12')
testCompile ('org.apache.maven:maven-ant-tasks:2.1.3')
testCompile ('org.robolectric:robolectric:3.0')
testCompile ('org.robolectric:shadows-support-v4:3.0')
}
sourceSets {
unitTest {
java.srcDirs = ['src/test/java']
resources.srcDirs = ['src/test/resources']
}
}
ClassLoader getClassLoader() {
List urls = sourceSets.test.runtimeClasspath.collect {
it.toURI().toURL()
}
return URLClassLoader.newInstance( urls as URL[] )
}
/**
* Filters out files that have specific annotation
* @param map - map of things to filter
* @return - list of acceptable files after filter
*/
List annotationFilter( Map map ) {
map.prefix = map?.prefix ?: '' // prefix: provide convenience for passing in annotation names
ClassLoader loader = classLoader
List result
// filter with annotations
if( !map.includes ) {
result = map?.names
} else {
result = []
map?.names.each { name ->
Class klass = loader.loadClass( name )
map?.includes.each { annotationName ->
String fullName = map.prefix + annotationName
Class annotation = loader.loadClass( fullName ).asSubclass( Annotation )
if( !klass.isAnnotationPresent( annotation ) ) {
result << name
}
}
}
}
if( result?.size() == 0 ) result = [ 'no.tests.to.run' ]
return result
}
/**
* Gradle task to run only robolectric tests.
*/
task unitTest( type: Test, description: 'Run all junit tests' ) {
android.sourceSets.main.java.srcDirs.each { dir ->
def buildDir = dir.getAbsolutePath().split('/')
buildDir = (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')
sourceSets.unitTest.compileClasspath += files(buildDir)
sourceSets.unitTest.runtimeClasspath += files(buildDir)
}
testClassesDir = sourceSets.unitTest.output.classesDir
classpath = sourceSets.unitTest.runtimeClasspath
doLast {
println "Doing Last"
List names = testClassNames()
List filtered = annotationFilter( names: names, includes: ['testUtils.RobolectricTest'] )
println 'Running ' + filtered.size() + ' tests:\n' + filtered*.toString()*.replaceAll('^','\t').join('\n')
filter {
setIncludePatterns( filtered as String[] )
}
}
}
答案 0 :(得分:2)
与Robolectric不同,但是在使用Gradle声明Android的自定义测试任务时,我遇到了很多麻烦。正如您所发现的,所有文档和示例都使用Java插件,但Android插件颠覆了大部分内容。
我在Android插件中找到的唯一解决方案是创建另一个构建类型,然后在Android插件中为我创建新的测试任务。然后我可以轻松修改任务。
以下是相关设置,我保存在<rootProject>/gradle/test.gradle
文件中(此特定示例使用类别注释将单元测试过滤到一个任务中,并将集成测试过滤到单独的任务中。有关该部分的信息,请参阅https://github.com/junit-team/junit4/wiki/Categories):
android {
buildTypes {
integration
}
testOptions {
unitTests.all {
useJUnit()
if (it.name == 'testIntegrationUnitTest') {
options {
excludeCategories 'com.example.categories.UnitTest'
}
} else {
options {
excludeCategories 'com.example.categories.IntegrationTest'
}
}
}
}
}
然后<module>/build.gradle
文件将从此文件中应用apply from: "../gradle/test.gradle"
这会导致合并两个文件的android
闭包,从而产生新的integration
构建类型,从而导致项目中的新testIntegrationUnitTest
任务标准testDebugUnitTest
和testReleaseUnitTest
任务。
但现在,testDebugUnitTest
仅运行&#34;真实&#34;单元测试,而testIntegrationUnitTest
仅运行集成测试。
您的里程/实施可能会有所不同。一旦你进入unitTest.all
关闭,你就可以对选项进行任何操作。
答案 1 :(得分:1)
自定义Gradle任务仅运行特定测试
在@ alphonzo79答案的基础上,我能够解决这个问题。
要知道的事情
完整的答案是创建一个自定义任务,将android testOptions的标志更改为excludeCategories。
CODE
def integrationTests = false
...
testOptions {
unitTests.all {
useJUnit()
if (integrationTests.toBoolean()) {
println "Integration Tests Only for " + it.name
options {
excludeCategories 'com.example.reactivemvp.categories.UnitTest'
}
} else {
println "Unit Tests Only for " + it.name
options {
excludeCategories 'com.example.reactivemvp.categories.IntegrationTest'
}
}
}
}
...
task integrationTest(
type: Test,
description: 'Run integration tests only. Pass in \'-Pintegration=true\'',
dependsOn: ['testDebugUnitTest', 'clean'] ) {
//Here for task completion, not actually used since sub task of testDebugUnitTest
testClassesDir = file("src/integrationTest/java/");
classpath = files("$System.env.ANDROID_HOME/sources/android-18")
//
//Turn on integration testing when argument exists and is true
//
if (project.hasProperty('integration')) {
println integration
if (integration == 'true') {
integrationTests = true
}
}
}
答案 2 :(得分:0)
你说Robolectric在Ubuntu上测试多维风味项目时找不到AndroidManifest.xml
尝试在@Config注释中显式提供清单文件的路径
@Config(constants = BuildConfig.class, manifest = "../<path to>/AndroidManifest.xml")
答案 3 :(得分:0)
我们可以使用以下配置按名称排除多个测试:
def integrationTests = false
android {
//...
testOptions {
unitTests {
includeAndroidResources = true
returnDefaultValues = true
all {
test {
filter {
if (integrationTests.toBoolean()) {
includeTestsMatching "*IntegrationTest"
} else {
includeTestsMatching "*UnitTest"
}
}
}
}
}
}
}
在命令行中:
gradlew test -->Run only *UnitTest