Gradle:使用注释过滤测试所需的指导 [英] Gradle: guidance needed to filter tests using annotation

查看:91
本文介绍了Gradle:使用注释过滤测试所需的指导的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在开发一个大型测试套件,用于在多种环境下运行,例如烟雾,性能,全套件等(我们目前使用JUnit作为测试框架)。我们试图实现的是注释包含一个或多个注释(如 @SmokeTest @PerformanceTest ,<$ c $)的测试(类或方法或两者) c> @AcceptanceTest ,然后在 build.gradle 中添加一些测试任务以运行基于这些注释的特定测试选择。这个想法与Gradle论坛上的这一个非常相似。



我知道Gradle可以基于JUnit注释检测JUnit测试(请参阅23.12.4。 gradle用户指南)。但是,我无法了解如何利用该功能并添加一些自己的自定义逻辑。我正在查找的内容如下所示:


  1. 根据一个或多个给定的注释(包括或
    排除)

  2. 将检测到的测试添加到某种类型的容器中。
  3. 让测试任务在容器中运行测试。

因此,我想问一下您可以提供的任何指导来实现该功能。非常感谢。

解决方案

经过一番研究,我想我现在已经有了解决方案。我在github上创建了演示项目。 (该项目的名称有点误导: - ])。

我也想粘贴解决方案的核心逻辑,这是从 build.gradle 在演示项目中:

  List testClassNames(){
文件classesDir = sourceSets.test.output.classesDir
字符串前缀= classesDir.toString()+'/'
列表名称= []
classesDir.traverse {
if(it.absolutePath.endsWith('.class')){
String name =(it.absolutePath - prefix).replaceAll('/','。') - '.class'
名字<<名称
}
}
返回名称
}

ClassLoader getClassLoader(){
列出url = sourceSets.test.runtimeClasspath.collect {
it.toURI()。toURL()
}
返回URLClassLoader.newInstance(url为URL [])
}

List annotationFilter(Map地图){
map.prefix = map?.prefix?:''// prefix:为传入注解名称提供便利

ClassLoader loader = classLoader

列表结果

//带注解的过滤
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(<名称
}
}
}
}

if(result?.size()== 0)result = ['no.tests.to .run']
返回结果
}

任务烟雾(类型:测试,描述:'运行烟雾测试'){
doFirst {
List names = testClassNames()
列表filtered = annotationFilter(names:names,包括:['demo.Smoke'])
println'Running'+ filtered.size()+'tests:\\\
' +过滤* .toString()*。replaceAll('^','\t')。join('\\\
')

filter {
setIncludePatterns(filtered as String [ ])
}
}
}

正如你所见在上面, smoke 任务将只执行用 @Smoke 注释的测试。


We are developing a large test suite which is intended to run on multiple environments, such as smoke, performance, full suite, etc. (We are currently using JUnit as the test framework.) What we are trying to achieve is annotate tests (classes or methods or both) with one or more annotations like @SmokeTest, @PerformanceTest, @AcceptanceTest and then add some test tasks in the build.gradle to run a specific selection of tests based on those annotations. The idea is very much like this one from the Gradle forum.

I know Gradle can detect JUnit tests based on JUnit annotations (see 23.12.4. Test detection in the gradle user guide). However, I cannot find out how I can leverage that capability and add some custom logics of my own. What I am looking for is something like below:

  1. Detect the tests based on one or more given annotations (include or exclude)
  2. Add the detected tests into a container of some sort.
  3. Have a test task to run tests in the container.

So, I would like to ask any guidance that you can provide to achieve that functionality. Thank you very much.

解决方案

After some research, I think I have solution now. I created a demo project at github. (The name of the project is a little misleading :-]).

I also would like to paste the core logic of the solution here, which is extracted from the build.gradle in the demo project:

List testClassNames() {
    File classesDir = sourceSets.test.output.classesDir
    String prefix = classesDir.toString() + '/'
    List names = []
    classesDir.traverse {
        if( it.absolutePath.endsWith( '.class' ) ) {
            String name = (it.absolutePath - prefix).replaceAll( '/', '.' ) - '.class'
            names << name
        }
    }
    return names
}

ClassLoader getClassLoader() {
    List urls = sourceSets.test.runtimeClasspath.collect {
        it.toURI().toURL()
    }
    return URLClassLoader.newInstance( urls as URL[] )
}

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<? extends Annotation> annotation = loader.loadClass( fullName ).asSubclass( Annotation )
                if( klass.isAnnotationPresent( annotation ) ) {
                    result << name
                }
            }
        }
    }

    if( result?.size() == 0 ) result = [ 'no.tests.to.run' ]
    return result
}

task smoke( type: Test, description: 'Run smoke tests' ) {
    doFirst {
        List names = testClassNames()
        List filtered = annotationFilter( names: names, includes: ['demo.Smoke'] )
        println 'Running ' + filtered.size() + ' tests:\n' + filtered*.toString()*.replaceAll('^','\t').join('\n')

        filter {
            setIncludePatterns( filtered as String[] )
        }
    }
}

As you can see above, the smoke task will only execute tests annotated with @Smoke.

这篇关于Gradle:使用注释过滤测试所需的指导的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆