TestNG系列:
TestNG和Junit4的参数化测试对比
TestNG运行指定测试套件
TestNG整合ReportNG
TestNG参数化测试实战
TestNG+Spring/Spring Boot整合
参数化测试是测试数据和测试脚本分离的一种实现方式,我们可以根据测试目的设计不同的测试数据并将测试数据存储在各种介质(内存、硬盘)中,测试方法在执行时获取一组预设的测试数据执行并给出结果
一、首先对比下TestNG和Junit的框架整合:
- Spring+TestNG+Maven整合:
1.pom.xml中增加testng依赖:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.8</version>
<scope>test</scope>
</dependency>
2.测试类增加1条注解
@ContextConfiguration(locations = "classpath:applicationContext.xml")并继承AbstractTestNGSpringContextTests,范例如下
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class BaseTest extends AbstractTestNGSpringContextTests{
@Test
public void testMethods()
{
......
}
}
- Spring+Junit+Maven整合:
1.pom.xml中增加junit依赖:
<!--Junit版本-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
2.测试类增加2条注解
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml"),如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class BaseTest{
@Test
public void testMethods()
{
......
}
}
二、再对比下二者参数化测试的实现:
Junit4 参数化测试:
- 步骤如下:
1.通过@Parameters标识静态参数构造方法
2.通过测试类构造方法引入参数
3.测试方法使用参数 - 源码如下:
@RunWith(Parameterized.class)
public class AuthorizedMemberHSFTest extends AuthorizedServiceTest {
private Long userId;
private String userName;
private String appName;
private String channelId;
private String secret;
private String xcodeAppKey;
private Long tenantId;
private boolean expected;
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{3253622341L, "arthur.hw", "ocs", "1703183528", "123456", "123", 905L, true},
{3253622341L, "arthur.hw", "ocs", "1703183528", "123456", "123", 905L, true}});
}
public AuthorizedMemberHSFTest(Long userId,
String userName,
String appName,
String channelId,
String secret,
String xcodeAppKey,
Long tenantId,
boolean expected) {
this.userId = userId;
this.userName = userName;
this.appName = appName;
this.channelId = channelId;
this.secret = secret;
this.xcodeAppKey = xcodeAppKey;
this.tenantId = tenantId;
this.expected = expected;
}
@Test
public void authorizeMember() {
// 01:prepare parameter
Credentials credentials = new Credentials();
credentials.setUserId(userId);
credentials.setUserName(userName);
credentials.setAppName(appName);
credentials.setChannelId(channelId); // channelId cant be null
credentials.setSecret(secret);
credentials.setXcodeAppKey(xcodeAppKey);
credentials.setTenantId(tenantId);
Result<AccessToken> result = new Result<AccessToken>();
// 02 hsf execution
try {
result = authorizeService.authorizeMember(credentials);
} catch (Exception ex) {
// log.error(ex.getMessage());
}
// 03 assert
Assert.assertEquals(result.isSuccess(), expected);
}
}
缺点:
- 1个测试类只能有一个静态的参数构造方法data()
- 测试类需要使用@RunWith(Parameterized.class),无法兼容spring-test的runner:@RunWith(SpringJUnit4ClassRunner.class),会导致无法通过注解注入待测服务
- 需要在测试类中添加一个构造方法(一种冗余设计)
TestNG 参数化测试:
- 步骤如下:
1.通过@dataProvider注解标识参数构造方法
2.测试方法在注解@Test中通过dataProvider属性指定参数构造方法,便可在测试方法中使用参数 - 源码如下:
public class AuthorizedServiceTest extends BaseTest {
@Resource
protected AuthorizeService authorizeService;
@BeforeClass
public void init() throws Exception {
ServiceUtil.waitServiceReady(authorizeService);
}
}
public class AuthorizedMemberHSFTest extends AuthorizedServiceTest {
@DataProvider
public static Object[][] getParameters(Method method) {
return new Object[][]{
{3253622341L, "arthur.hw", "ocs", "1703183528", "123456", "123", 905L, true},
{1L, "obama", "ocs", "323243242", "123", "123", 3L, true}};
}
@Test(dataProvider = "getParameters")
public void authorizeMember(Long userId,
String userName,
String appName,
String channelId,
String secret,
String xcodeAppKey,
Long tenantId,
boolean expected) {
// 01:prepare parameter
Credentials credentials = new Credentials();
credentials.setUserId(userId);
credentials.setUserName(userName);
credentials.setAppName(appName);
credentials.setChannelId(channelId);
credentials.setSecret(secret);
credentials.setXcodeAppKey(xcodeAppKey);
credentials.setTenantId(tenantId);
Result<AccessToken> result = new Result<AccessToken>();
// 02 hsf execution
try {
result = authorizeService.authorizeMember(credentials);
} catch (Exception ex) {
log.error(ex.getMessage());
}
// 03 assert
Assert.assertEquals(result.isSuccess(), expected);
}
}
执行结果:
除此之外,TestNG还支持通过testng.xml构造参数:
1.这次我们使用maven来运行TestNG,可以参考http://maven.apache.org/surefire/maven-surefire-plugin/examples/testng.html
2.在src/test/java/resources下添加testng.xml文件,其中通过<parameter/>构造需要使用的参数和值
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="testmain" verbose="1" >
<parameter name="kilo" value="just for test"></parameter>
<test name="authorizeService" >
<classes>
<class name="xxx.yyy.AuthorizedServiceTest" />
</classes>
</test>
</suite>
3.在pom.xml中添加maven-surfire-plugin插件配置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
4.测试方法添加参数引用:
@Parameters({"kilo"})
@Test
public void authorizeServiceTestMethod(String kilo)
{
System.out.println(kilo);
}
5.运行test:
mvn clean test
TestNG的参数化测试还有一些高级特性,具体可以参考:http://testng.org/doc/documentation-main.html#parameters
可以看到,TestNG相比Junit,基本Junit参数化测试的缺点都解决了:
1、一个测试类中可以有多个参数构造方法,测试方法和参数构造方法可以通过注解关联起来
2、可以兼容spring的注解注入
3、无需添加构造方法
同时代码量较小