mvn test 和 的区别 mvn surefire:test
以这两种方式运行它的区别在于:
mvn -Dtest=DatabaseTest test
mvn -Dtest=DatabaseTest surefire:test
我可以看到测试显示:
执行mvn test 执行的输出
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ rac.mybatis ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ rac.mybatis ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ rac.mybatis ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/etomort/smip/oracle-rac/mybatis-rac/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ rac.mybatis ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ rac.mybatis ---
[INFO] Surefire report directory: /home/etomort/smip/oracle-rac/mybatis-rac/target/surefire-reports
surefire:test 的输出:
[INFO] --- maven-surefire-plugin:2.12.4:test (default-cli) @ rac.mybatis ---
[INFO] Surefire report directory: /home/etomort/smip/oracle-rac/mybatis-rac/target/surefire-reports
不同之处在于test
运行完整构建到执行测试的点,而surefire:test
仅执行测试,重新使用先前构建的中间结果。
所以,如果你是编辑测试并且只运行surefire:test
,新版本的测试将不会被编译,因此Maven将执行一些旧版本的测试。一般来说,很难说以这种方式执行哪个版本的测试,因此这就是人们通常使用mvn clean test
而不是mvn surefire:test
的原因。
Surefire是官方测试插件,必将进入测试阶段。
maven是使用surefire插件执行测试的,它按照指定格式的类名在src/test/java/目录下来查找匹配的测试类
默认包含的测试类:
**/*Test.java
**/Test*.java
**/*TestCase.java
默认排除的测试类:
**/Abstract*Test.java
**/Abstract*TestCase.java
因此默认情况下,诸如“add_exist_department.java”或者“add_exist_departmentTests.java”这种JUnit类或者Testng是不会被Maven发现并执行的,可按如下修改surefire插件的配置以达到包含"**/*Tests.java"测试类的目的:
org.apache.maven.plugins
maven-surefire-plugin
**/*Tests.java
**/Abstract*.java
详细教程见:
Maven Surefire Plugin – Inclusions and Exclusions of Tests
运行所有的测试类:
> mvn test
运行指定的测试类:
> mvn test -Dtest=[ClassName]
该命令支持通配符,也就是mvn tes -Dtest=Hello*Test,这样就会运行测试以Hello开头和Test结尾的所有测试用例,
也可以用逗号分隔一次执行多个测试用例, 具体的扩展使用可以查看官方文档
运行测试类中指定的方法:(这个需要maven-surefire-plugin:2.7.3以上版本才能支持)
> mvn test -Dtest=[ClassName]#[MethodName]
[MethodName]为要运行的方法名,支持*通配符,范例:
1) >mvn test -Dtest=MyClassTest#test1
2) >mvn test -Dtest=MyClassTest#*test*
如果你执行过mvn test
或者执行其他maven命令时跑了测试用例,你就已经用过maven-surefire-plugin
了。maven-surefire-plugin
是maven里执行测试用例的插件,不显示配置就会用默认配置。这个插件的surefire:test
命令会默认绑定maven执行的test
阶段。
maven的生命周期有哪些阶段?
[validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes,
test
, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy]
如果说maven已经有了maven-surefire-plugin的默认配置,我们还有必要了解maven-surefire-plugin的配置么?答案是肯定的。虽说maven-surefire-plugin有默认配置,但是当需要修改一些测试执行的策略时,就有必要我们去重新配置这个插件了。
Maven官网查看插件如何使用
Maven – Available Plugins
点击进入surefire的技术文档
先引入Junit依赖包
[...]
junit
junit
4.12
test
[...]
最简单的配置方式就不配置或者是只声明插件。
org.apache.maven.plugins
maven-surefire-plugin
2.19
这个时候maven-surefire-plugin会按照如下逻辑去寻找JUnit的版本并执行测试用例。
if the JUnit version in the project >= 4.7 and the parallel attribute has ANY value
use junit47 provider
if JUnit >= 4.0 is present
use junit4 provider
else
use junit3.8.1
当然,如果你明确用的是JUnit4.7及以上版本,可以明确声明:
org.apache.maven.plugins
maven-surefire-plugin
2.19
org.apache.maven.surefire
surefire-junit47
2.19
JUnit4.0(含)到JUnit4.7(不含)的版本,这样声明:
org.apache.maven.plugins
maven-surefire-plugin
2.19
org.apache.maven.surefire
surefire-junit4
2.19
JUnit3.8(含)到JUnit4.0(不含)的版本,这样声明:
org.apache.maven.plugins
maven-surefire-plugin
2.19
org.apache.maven.surefire
surefire-junit3
2.19
JUnit3.8以下的版本surefire不支持。建议大家用最新的JUnit版本,目前是4.12
[...]
junit
junit
4.12
test
[...]
本文的例子我们用的Junit4.12.
2.2. 使用Testng组件进行测试
2.2.1 引入 Testng依赖包
[...]
org.testng
testng
6.9.8
test
[...]
如果用你的依赖是 TestNG 版本(<= 5.11),则要如下配置
[...]
org.testng
testng
5.11
test
jdk15
[...]
src/test/java目录下
*Test.java格式的类被执行
Testng比传统的Junit单元测试多了支出Suite XML Files 用来指定执行某些测试套件(Junit不支出,只能)
如:
[...]
org.apache.maven.plugins
maven-surefire-plugin
3.0.0-M5
testng.xml
[...]
如:
Maven surefire插件用于运行项目测试。 它还允许我们配置在构建项目时要执行的XML套件。 下面的配置将告诉Maven testng.xml
插件仅执行testng.xml
和test_parameters.xml
测试套件文件。
org.apache.maven.plugins
maven-surefire-plugin
2.21.0
src/test/resources/testng.xml
src/test/resources/test_parameters.xml
我们现在准备两个类,一个被测试的类,一个测试用例.目录结构如下
现在我们准备一个简单的类.
package com.qyf404.learn.maven;
public class App {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
再创建一个测试用例.
package com.qyf404.learn.maven;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class AppTest {
private App app;
@Before
public void setUp() {
app = new App();
}
@Test
public void testAdd() throws InterruptedException {
int a = 1;
int b = 2;
int result = app.add(a, b);
Assert.assertEquals(a + b, result);
}
@Test
public void testSubtract() throws InterruptedException {
int a = 1;
int b = 2;
int result = app.subtract(a, b);
Assert.assertEquals(a - b, result);
}
@After
public void tearDown() throws Exception {
}
}
用maven执行测试用例很简单,直接运行mvn test
就可以.一般我们执行maven打包命令mvn package
前maven会默认执行test
命令.
qyfmac$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building learn-maven 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ learn-maven ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/qyfmac/git/learn-maven/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ learn-maven ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /Users/qyfmac/git/learn-maven/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ learn-maven ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/qyfmac/git/learn-maven/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ learn-maven ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 2 source files to /Users/qyfmac/git/learn-maven/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.19:test (default-test) @ learn-maven ---
[WARNING] The parameter forkMode is deprecated since version 2.14. Use forkCount and reuseForks instead.
[INFO] Surefire report directory: /Users/qyfmac/git/learn-maven/target/surefire-reports
[INFO] Using configured provider org.apache.maven.surefire.junit4.JUnit4Provider
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.qyf404.learn.maven.AppTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec - in com.qyf404.learn.maven.AppTest
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.622 s
[INFO] Finished at: 2015-12-01T11:36:04+08:00
[INFO] Final Memory: 14M/228M
[INFO] ------------------------------------------------------------------------
qyfmac$
其实我们会发现关键内容还是JUnit的东西,maven只是作为一个调用器调用了一下这些测试用例.
后面让我们来研究一下maven-surefire-plugin
这个插件更多的知识,这些多数都是和配置相关的.
在工作中,很多情况下我们打包是不想执行测试用例的,可能是测试用例不完事,或是测试用例会影响数据库数据.跳过测试用例执行过程有三个种方法.
在插件的configuration配置中声明跳过测试用例
org.apache.maven.plugins
maven-surefire-plugin
2.19
org.apache.maven.surefire
surefire-junit47
2.19
true
在properties配置中声明跳过测试用例
true
或
true
在执行maven命令时可以声明跳过测试用例
qyfmac$ mvn test -Dmaven.test.skip=true
或
qyfmac$ mvn test -DskipTests=true
首先分两种情况,一种是配置skipTests
,一种是配置maven.test.skip
(真要命,声明位置就三处了,还搞出两个变量名,一共就是5中情况).
如果是配置skipTests
, configuration的配置优先级最高,命令中得配置次之, properties的配置最低.
即configuration > 命令 > properties
如果是配置maven.test.skip
,命令中得配置优先级最高, properties的配置最低.
即命令 > properties
skipTests
和maven.test.skip
有一个被设置成了true,则跳过测试用例.
即skipTests||maven.test.skip
决定是否跳过测试用例执行.
很多情况下我们写完一个测试用例后,想马上运行一下,看看执行情况.如果用IDE开发,里面一般都有直接运行一个测试用例的方法.但是如果用maven命令达到同样的效果,就需要加些命令参数了.
比如我们现在再加一个测试用例App2Test.java.
package com.qyf404.learn.maven;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class App2Test {
private App app;
@Before
public void setUp() {
app = new App();
}
@Test
public void testAdd() throws InterruptedException {
int a = 1;
int b = 2;
int result = app.add(a, b);
Thread.currentThread().sleep(1000);
Assert.assertEquals(a + b, result);
}
@After
public void tearDown() throws Exception {
}
}
直接运行 mvn test是这样的,它执行了全部测试用例.
qyfmac$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building learn-maven 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.qyf404.learn.maven.App2Test
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.004 sec - in com.qyf404.learn.maven.App2Test
Running com.qyf404.learn.maven.AppTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 sec - in com.qyf404.learn.maven.AppTest
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.773 s
[INFO] Finished at: 2015-12-01T14:57:00+08:00
[INFO] Final Memory: 9M/156M
[INFO] ------------------------------------------------------------------------
现在我们用命令mvn test -Dtest=App2Test
指定执行App2Test.
qyfmac$ mvn test -Dtest=App2Test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building learn-maven 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.qyf404.learn.maven.App2Test
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.003 sec - in com.qyf404.learn.maven.App2Test
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.061 s
[INFO] Finished at: 2015-12-01T14:58:59+08:00
[INFO] Final Memory: 9M/156M
[INFO] ------------------------------------------------------------------------
-Dtest
的参数是可以用表达式的.
比如执行多个测试用例可以用逗号分开 mvn test -Dtest=App2Test,AppTest
.
也可以用ant风格的路径表达式mvn test -Dtest=*2Test
,mvn test -Dtest=???2Test
.
甚至指定具体的测试方法mvn test -Dtest=*Test#testAdd
.
指定具体包里的测试用例mvn test -Dtest=com/qyf404/learn/maven/*
.
上面说了,在执行命令时可以指定执行哪个或哪些测试用例,其实在pom.xml里也是可以配置的.
比如打包时执行测试用例AppTest,不执行App2Test,可以这么配置.
org.apache.maven.plugins
maven-surefire-plugin
2.19
org.apache.maven.surefire
surefire-junit47
2.19
**/AppTest.java
**/App2Test.java
和
里的配置方式和-Dtest
后面的一样可以配置表达式:
指定具体类
.
指定具体类
.
指定具体类
.
指定具体类
.
指定具体类
.
叹号[!]表示否定
.
使用ant风格的路径表达式
.
使用ant风格的路径表达式
.
更复杂的%regex[expr]
表达式
.
更复杂的%regex[expr]
表达式
.
更复杂的%regex[expr]
表达式
,中间的方括号表示或的概念,即learn或test的情况.
更复杂的%regex[expr]
表达式
,这里面的叹号表示否定,即包含不符合该表达式的测试用例.
更复杂的%regex[expr]
表达式
,这种配置方式忽略了包前缀,可以理解成倒着匹配全类名.
更复杂的%regex[expr]
表达式里最好不要有问号[?],而且匹配的是类的全类名.
不可以指定具体方法,这种配置是错误的
.
不可以指定java文件在%regex[expr]
里具体方法,这种配置是错误的
.
如果同时配置了
和
,最终执行的测试用例是二者的交集.
上面我们说了,可以配置
这些信息来控制执行哪些测试用例,但是JUnit里有个注解@Category
可以对测试用例组分组标记,而用maven执行测试用例时,我们也可以根据这个注解的标记,来确定执行哪组测试用例.
比如我们的测试用例是这样的:
package com.qyf404.learn.maven;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
public class AppTest {
private App app;
@Before
public void setUp() {
app = new App();
}
@Test
@Category(com.qyf404.learn.maven.FastTests.class)
public void testAdd() throws InterruptedException {
int a = 1;
int b = 2;
int result = app.add(a, b);
System.out.println("---" + Thread.currentThread().getName());
Assert.assertEquals(a + b, result);
}
@Test()
@Category(com.qyf404.learn.maven.SlowTests.class)
public void testSubtract() throws InterruptedException {
int a = 1;
int b = 2;
int result = app.subtract(a, b);
System.out.println("---" + Thread.currentThread().getName());
Assert.assertEquals(a - b, result);
}
@After
public void tearDown() throws Exception {
}
}
pom.xml里这么配置:
org.apache.maven.plugins
maven-surefire-plugin
2.19
com.qyf404.learn.maven.SlowTests
1
2
在执行mvn test
时,则只执行标记@Category(com.qyf404.learn.maven.SlowTests.class)
的测试用例.
在打包时,默认情况会执行全部测试用例,然后给出一个执行的统计结果,如下所示:
Results :
Tests run: 3, Failures: 1, Errors: 0, Skipped: 0
很多情况下我们希望测试用例没有失败的才能打包,如果出现打包失败,需要立刻停止执行其他测试用例.为满足这个要求,我们需要增加一些配置设定.
1
里面的数字1
表示当有一个测试用例执行失败或发生异常时,跳过后续的其他测试用例.这个数字其实只要是一个大于零的数就可以.表达的意思就是当有N
个测试用例执行失败或异常时,跳过后续的其他测试用例.
当我们的一个测试用例测试的是一个远程服务,在某些情况下可能由于环境问题(比如网络)导致测试用例执行失败,但这并不是程序问题.换句话说,当一个测试用例执行N次,有一次执行成功就认为成功.这个时候我们就需要配置一个参数,运行执行失败的此时用例重新执行.
2
里面的数字2
表示当某个测试用例执行失败以后,还可以重新执行2次,有一次执行成功就认为测试用例执行成功.里面的2
只要是一个大于零的整数就可以,表示重试次数.如果发生重试,在maven的执行报告中会多一个Flakes.
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.qyf404.learn.maven.App2Test
Tests run: 3, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 3.023 sec <<< FAILURE! - in com.qyf404.learn.maven.App2Test
testAdd(com.qyf404.learn.maven.App2Test) Time elapsed: 1.012 sec <<< FAILURE!
java.lang.AssertionError: expected:<2> but was:<3>
at com.qyf404.learn.maven.App2Test.testAdd(App2Test.java:32)
testAdd(com.qyf404.learn.maven.App2Test) Time elapsed: 1.006 sec <<< FAILURE!
java.lang.AssertionError: expected:<2> but was:<3>
at com.qyf404.learn.maven.App2Test.testAdd(App2Test.java:32)
Running com.qyf404.learn.maven.AppTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 sec - in com.qyf404.learn.maven.AppTest
Results :
Flaked tests:
com.qyf404.learn.maven.App2Test.testAdd(com.qyf404.learn.maven.App2Test)
Run 1: App2Test.testAdd:32 expected:<2> but was:<3>
Run 2: App2Test.testAdd:32 expected:<2> but was:<3>
Run 3: PASS
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Flakes: 1
一般情况我们可以在IDE中直接执行测试用例,有时候会出现这种情况,IED中直接执行测试用例是没问题的,但是用maven命令打包时就执行失败了.我们可以在命令中加入-X
或--debug
来打印更多的日志信息来排查问题.但也可以开启JVM的调试端口来远程debug.
执行maven命令mvn -Dmaven.surefire.debug test
以开启调试模式.当然也可以用完整的命令来指定端口
mvn -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 -Xnoagent -Djava.compiler=NONE" test
命令执行后是这个样子:
qyfmac$ mvn -Dmaven.surefire.debug test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building learn-maven 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ learn-maven ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/qyfmac/git/learn-maven/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ learn-maven ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ learn-maven ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/qyfmac/git/learn-maven/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ learn-maven ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.19:test (default-test) @ learn-maven ---
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Listening for transport dt_socket at address: 5005
后面我们就需要根据这个5005
端口去启动本地源码了.
开始调试前需要先配置IDE,我以idea为例说明如何配置.
Edit Configurations...
. Remote
. 如果测试用例很多,而且并行执行时不会互相影响,这时我们可以配置一个线程数来加快测试用例的执行效率.
org.apache.maven.plugins
maven-surefire-plugin
2.19
methods
10
在执行完mvn test
后,会在target
目录下生成测试报告
一共两个文件,txt文件记录了汇总信息,xml文件里记录了测试用例执行的环境和执行情况,而且方便程序解析展现.
txt文件内容:
-------------------------------------------------------------------------------
Test set: com.qyf404.learn.maven.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec - in com.qyf404.learn.maven.AppTest
xml文件内容:
...
写了这么多,基本上把maven-surefire-plugin
这个插件常用的都介绍了.但是maven-surefire-plugin
没介绍的远比这些多,看看它的配置项就知道了.
再加上依据测试结果展现的测试报告就更多了.如果想更加深入了解可以到官网学习.