背景:我用Jenkins做CI,并同时加Sonar做单元测试和质量扫描。
大家都知道,让Maven过滤掉单元测试一般会使用 -Dmaven.test.skip=true(即不编译单元测试代码,也不运行单元测试)。
但是如果直接用-Dmaven.test.skip=true会导致Sonar也不跑单元测试。
技巧:使用-Dtest -DfailIfNoTests=false 让单元测试仅仅在Sonar扫描时启动。
解释:
下面是官方对于“test”和“failIfNoTests”的解释:
test | String | - | Specify this parameter to run individual tests by file name, overriding theincludes/excludes parameters. Each pattern you specify here will be used to create an include pattern formatted like **/${test}.java, so you can just type "-Dtest=MyTest" to run a single test called "foo/MyTest.java". This parameter overrides the includes/excludes parameters, and the TestNGsuiteXmlFiles parameter. Since 2.7.3, you can execute a limited number of methods in the test by adding #myMethod or #my*ethod. For example, "-Dtest=MyTest#myMethod". This is supported for junit 4.x and testNg. User property is: test |
failIfNoTests | Boolean | 2.4 | Set this to "true" to cause a failure if there are no tests to run. Defaults to "false". User property is: failIfNoTests. |
(1)可以看出“test”参数的标准用法应该是:-Dtest=MyTest#myMethod(使用正则表达式匹配需要运行的单元测试)。
使用“-Dtest”,实质等同于“-Dtest=<空值>”。因此肯定匹配不到任何单元测试类,从而达到跳过单元测试的效果。
(2)使用“-DfailIfNoTests=false”是为了取消因为“-Dtest”导致没有任何单元测试运行而抛出的异常。(有单元测试,但一个都没运行,maven会以任务失败来表示警告)
(3)最重要的一点是:Sonar运行时的maven-surefire-plugin竟然不认上述-Dtest的过滤作用。
具体原因没有深究,不过通过比较日志中的maven-surefire-plugin的goal,就能发现端倪了:
maven-surefire-plugin:2.12.4:test (default-test)【正常mvn的goal】
maven-surefire-plugin:2.12.4:test (default-cli) 【sonar的goal】
坏处:如果单元测试运行失败,或出现运行时异常等,Jenkins JOB的状态不会发生改变。
因为,maven构建时,跳过了单元测试,所以即使单元测试出现问题,Jenkins JOB的状态也不会变化。
并且,Sonar运行的结果也不会影响Jenkins JOB的状态。