pom.xml
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
<!--如果这里一直引用失败,那么就在父项目的pom文件中引入-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
</dependency>
<!--引入测试报告相关包-->
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.41.1</version>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.0.6</version>
</dependency>
</dependencies>
application.properties
test.url=http://localhost:8888
#ç»éæ¥å£uri
login.uri=/v1/login
#æ´æ°ç¨æ·ä¿¡æ¯æ¥å£uri
updateUserInfo.uri=/v1/updateUserInfo
#è·åç¨æ·å表æ¥å£uri
getUserList.uri=/v1/getUserInfo
#è·åç¨æ·ä¿¡æ¯æ¥å£uri
getUserInfo.uri=/v1/getUserInfo
#æ·»å ç¨æ·æ¥å£uri
addUser.uri=/v1/addUser
databaseConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 注册对象的空间命名 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 1.加载数据库驱动 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- 2.数据库连接地址 -->
<property name="url" value="jdbc:mysql://192.168.1.7:3306/course"/>
<!-- 数据库用户... -->
<property name="username" value="admin"/>
<!-- 数据库密码... -->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 注册映射文件:java对象与数据库之间的xml文件路径! -->
<mappers>
<mapper resource="mapper/SQLMapper.xml"/>
</mappers>
</configuration>
testng.xml
<?xml version="1.0" encoding="UTF-8" ?>
<suite name="用户管理系统测试套件">
<test name="用户管理系统测试用例">
<classes>
<class name="com.tester.cases.LoginTest">
<methods>
<include name="loginTrue"/>
<include name="loginFalse"/>
</methods>
</class>
<!--<class name="com.tester.cases.AddUserTest">-->
<!--<methods>-->
<!--<include name="addUser"/>-->
<!--</methods>-->
<!--</class>-->
<!--<class name="com.tester.cases.GetUserInfoTest">-->
<!--<methods>-->
<!--<include name="getUserInfo"/>-->
<!--</methods>-->
<!--</class>-->
<!--<class name="com.tester.cases.UpdateUserInfoTest">-->
<!--<methods>-->
<!--<include name="updateUserInfo"/>-->
<!--<include name="deleteUser"/>-->
<!--</methods>-->
<!--</class>-->
<class name="com.tester.cases.GetUserInfoListTest">
<methods>
<include name="getUserListInfo"/>
</methods>
</class>
</classes>
</test>
<listeners>
<listener class-name="com.tester.config.ExtentTestNGIReporterListener" />
</listeners>
</suite>
SQLMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 命名空间mapper,如果有多个mapper文件,这个必须唯一 -->
<mapper namespace="com.tester.model">
<!--获取登陆接口case-->
<select id="loginCase" parameterType="Integer" resultType="com.tester.model.LoginCase">
select * from loginCase
where id = #{id};
</select>
<!--添加用户接口case-->
<select id="addUserCase" parameterType="Integer" resultType="com.tester.model.AddUserCase">
select * from addUserCase where id=#{id};
</select>
<!--获取用户信息case-->
<select id="getUserInfoCase" parameterType="Integer" resultType="com.tester.model.GetUserInfoCase">
<!-- SQL语句 -->
select * from getUserInfoCase where id=#{id};
</select>
<!--获取用户列表case-->
<select id="getUserListCase" parameterType="Integer" resultType="com.tester.model.GetUserListCase">
<!-- SQL语句 -->
select * from getUserListCase where id=#{id};
</select>
<!--更新/删除用户信息case-->
<select id="updateUserInfoCase" parameterType="Integer" resultType="com.tester.model.UpdateUserInfoCase">
select * from updateUserInfoCase where id = #{id};
</select>
<!--添加用户接口-->
<select id="addUser" parameterType="com.tester.model.AddUserCase" resultType="com.tester.model.User">
select * from user where
userName=#{userName}
and password=#{password}
and sex=#{sex}
and age=#{age}
and permission=#{permission}
and isDelete=#{isDelete};
</select>
<!--获取用户信息-->
<select id="getUserInfo" parameterType="com.tester.model.GetUserInfoCase" resultType="com.tester.model.User">
<!-- SQL语句 -->
select * from user where
id=#{userId};
</select>
<!--获取用户列表-->
<select id="getUserList" parameterType="com.tester.model.GetUserListCase" resultType="com.tester.model.User">
<!-- SQL语句 -->
select * from user
<trim prefix="WHERE" prefixOverrides="and">
<if test="null != userName and '' !=userName">
AND userName=#{userName}
</if>
<if test="null != sex and '' !=sex">
AND sex=#{sex}
</if>
<if test="null != age and '' !=age">
AND age=#{age}
</if>
</trim>
;
</select>
<!--获取更新后的数据-->
<select id="getUpdateUserInfo" parameterType="com.tester.model.UpdateUserInfoCase" resultType="com.tester.model.User">
select * from user
<trim prefix="WHERE" prefixOverrides="and">
<if test="null != userName and '' !=userName">
AND userName=#{userName}
</if>
<if test="null != sex and '' !=sex">
AND sex=#{sex}
</if>
<if test="null != age and '' !=age">
AND age=#{age}
</if>
<if test="null != permission and '' !=permission">
AND permission=#{permission}
</if>
<if test="null != isDelete and '' !=isDelete">
AND isDelete=#{isDelete}
</if>
</trim>
And id = #{userId};
</select>
</mapper>
Utils:
ConfigFile
package com.tester.utils;
import com.tester.model.InterfaceName;
import java.util.Locale;
import java.util.ResourceBundle;
public class ConfigFile {
private static ResourceBundle bundle= ResourceBundle.getBundle("application", Locale.CHINA);;
public static String getUrl(InterfaceName name){
String address = bundle.getString("test.url");
String uri = "";
String testUrl;
if(name == InterfaceName.GETUSERLIST){
uri = bundle.getString("getUserList.uri");
}
if(name == InterfaceName.LOGIN){
uri = bundle.getString("login.uri");
}
if(name == InterfaceName.UPDATEUSERINFO){
uri = bundle.getString("updateUserInfo.uri");
}
if(name == InterfaceName.GETUSERINFO){
uri = bundle.getString("getUserInfo.uri");
}
if(name == InterfaceName.ADDUSERINFO){
uri = bundle.getString("addUser.uri");
}
testUrl = address + uri;
return testUrl;
}
}
DatabaseUtil
package com.tester.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
public class DatabaseUtil {
public static SqlSession getSqlSession() throws IOException {
//获取配置的资源文件
Reader reader = Resources.getResourceAsReader("databaseConfig.xml");
//得到SqlSessionFactory,使用类加载器加载xml文件
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//得到sqlsession对象,这个对象就能执行配置文件中的sql语句啦
SqlSession session = factory.openSession();
return session;
}
}
config
--ExtentTestNGIReporterListener
package com.tester.config;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.ResourceCDN;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.model.TestAttribute;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
import org.testng.*;
import org.testng.xml.XmlSuite;
import java.io.File;
import java.util.*;
public class ExtentTestNGIReporterListener implements IReporter {
//生成的路径以及文件名
private static final String OUTPUT_FOLDER = "test-output/";
private static final String FILE_NAME = "index.html";
private ExtentReports extent;
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
init();
boolean createSuiteNode = false;
if(suites.size()>1){
createSuiteNode=true;
}
for (ISuite suite : suites) {
Map<String, ISuiteResult> result = suite.getResults();
//如果suite里面没有任何用例,直接跳过,不在报告里生成
if(result.size()==0){
continue;
}
//统计suite下的成功、失败、跳过的总用例数
int suiteFailSize=0;
int suitePassSize=0;
int suiteSkipSize=0;
ExtentTest suiteTest=null;
//存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
if(createSuiteNode){
suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());
}
boolean createSuiteResultNode = false;
if(result.size()>1){
createSuiteResultNode=true;
}
for (ISuiteResult r : result.values()) {
ExtentTest resultNode;
ITestContext context = r.getTestContext();
if(createSuiteResultNode){
//没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
if( null == suiteTest){
resultNode = extent.createTest(r.getTestContext().getName());
}else{
resultNode = suiteTest.createNode(r.getTestContext().getName());
}
}else{
resultNode = suiteTest;
}
if(resultNode != null){
resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());
if(resultNode.getModel().hasCategory()){
resultNode.assignCategory(r.getTestContext().getName());
}else{
resultNode.assignCategory(suite.getName(),r.getTestContext().getName());
}
resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
resultNode.getModel().setEndTime(r.getTestContext().getEndDate());
//统计SuiteResult下的数据
int passSize = r.getTestContext().getPassedTests().size();
int failSize = r.getTestContext().getFailedTests().size();
int skipSize = r.getTestContext().getSkippedTests().size();
suitePassSize += passSize;
suiteFailSize += failSize;
suiteSkipSize += skipSize;
if(failSize>0){
resultNode.getModel().setStatus(Status.FAIL);
}
resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));
}
buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);
buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);
buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);
}
if(suiteTest!= null){
suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));
if(suiteFailSize>0){
suiteTest.getModel().setStatus(Status.FAIL);
}
}
}
// for (String s : Reporter.getOutput()) {
// extent.setTestRunnerOutput(s);
// }
extent.flush();
}
private void init() {
//文件夹不存在的话进行创建
File reportDir= new File(OUTPUT_FOLDER);
if(!reportDir.exists()&& !reportDir .isDirectory()){
reportDir.mkdir();
}
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
// 设置静态文件的DNS
//怎么样解决cdn.rawgit.com访问不了的情况
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
htmlReporter.config().setDocumentTitle("api自动化测试报告");
htmlReporter.config().setReportName("api自动化测试报告");
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
}
private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {
//存在父节点时,获取父节点的标签
String[] categories=new String[0];
if(extenttest != null ){
List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
categories = new String[categoryList.size()];
for(int index=0;index<categoryList.size();index++){
categories[index] = categoryList.get(index).getName();
}
}
ExtentTest test;
if (tests.size() > 0) {
//调整用例排序,按时间排序
Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {
@Override
public int compare(ITestResult o1, ITestResult o2) {
return o1.getStartMillis()<o2.getStartMillis()?-1:1;
}
});
treeSet.addAll(tests.getAllResults());
for (ITestResult result : treeSet) {
Object[] parameters = result.getParameters();
String name="";
//如果有参数,则使用参数的toString组合代替报告中的name
for(Object param:parameters){
name+=param.toString();
}
if(name.length()>0){
if(name.length()>50){
name= name.substring(0,49)+"...";
}
}else{
name = result.getMethod().getMethodName();
}
if(extenttest==null){
test = extent.createTest(name);
}else{
//作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
test = extenttest.createNode(name).assignCategory(categories);
}
//test.getModel().setDescription(description.toString());
//test = extent.createTest(result.getMethod().getMethodName());
for (String group : result.getMethod().getGroups())
test.assignCategory(group);
List<String> outputList = Reporter.getOutput(result);
for(String output:outputList){
//将用例的log输出报告中
test.debug(output);
}
if (result.getThrowable() != null) {
test.log(status, result.getThrowable());
}
else {
test.log(status, "Test " + status.toString().toLowerCase() + "ed");
}
test.getModel().setStartTime(getTime(result.getStartMillis()));
test.getModel().setEndTime(getTime(result.getEndMillis()));
}
}
}
private Date getTime(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();
}
}
--TestConfig
package com.tester.config;
import lombok.Data;
import org.apache.http.client.CookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
@Data
public class TestConfig {
//登陆接口uri
public static String loginUrl;
//更新用户信息接口uri
public static String updateUserInfoUrl;
//获取用户列表接口uri
public static String getUserListUrl;
//获取用户信息接口uri
public static String getUserInfoUrl;
//添加用户信息接口
public static String addUserUrl;
//用来存储cookies信息的变量
public static CookieStore store;
//声明http客户端
public static DefaultHttpClient defaultHttpClient;
}
model
AddUserCase
package com.tester.model;
import lombok.Data;
@Data
public class AddUserCase {
private String userName;
private String password;
private String sex;
private String age;
private String permission;
private String isDelete;
private String expected;
}
GetUserInfoCase
package com.tester.model;
import lombok.Data;
@Data
public class GetUserInfoCase {
private int userId;
private String expected;
}
GetUserListCase
package com.tester.model;
import lombok.Data;
@Data
public class GetUserListCase {
private String userName;
private String age;
private String sex;
private String expected;
}
InterfaceName
package com.tester.model;
public enum InterfaceName {
GETUSERLIST,LOGIN,UPDATEUSERINFO,GETUSERINFO,ADDUSERINFO
}
LoginCase
package com.tester.model;
import lombok.Data;
@Data
public class LoginCase {
private int id;
private String userName;
private String password;
private String expected;
}
UpdateUserInfoCase
package com.tester.model;
import lombok.Data;
@Data
public class UpdateUserInfoCase {
private int id;
private int userId;
private String userName;
private String sex;
private String age;
private String permission;
private String isDelete;
private String expected;
}
User
package com.tester.model;
import lombok.Data;
@Data
public class User {
private int id;
private String userName;
private String password;
private String age;
private String sex;
private String permission;
private String isDelete;
@Override
public String toString(){
return (
"id:"+id+","+
"userName:"+userName+","+
"password:"+password+","+
"age:"+age+","+
"sex:"+sex+","+
"permission:"+permission+","+
"isDelete:"+isDelete+"}"
);
}
}