目录
- 1、目录结构的相关类
- cases类
- 1、添加用户 AddUserTest
- 2、获取用户列表信息 GetUserInfoListTest
- 3、获取用户信息 GetUserInfoTest
- 4、登录测试
- 5、更新用户信息
- config类
- 1、报告配置
- 2、用户路径配置
- model类
- utils类
- 配置配置类
- SQLMapper.xml
- spring boot全局配置
- databaseConfig.xml
- testng.xml配置
- 测试
- 1、前提条件
- 第一步:首先mock数据
- 第二步:启动服务
- 第三步::使用postman测试mock服务是否可用
- 第四步:数据的准备 准备用户名等于 abc的数(用于登录结果的验证)
- 2、已登录成功案例测试为例:
- 2.1、直接在用例里面测试验证是否能用
- 2.2、在xml测试套件是否可用
1、目录结构的相关类
cases类
1、添加用户 AddUserTest
import com.tester.config.TestConfig;
import com.tester.model.AddUserCase;
import com.tester.model.User;
import com.tester.utils.DatabaseUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
public class AddUserTest {
//需要依赖loginTrue的分组的用例
@Test(dependsOnGroups = "loginTrue",description = "添加用户接口接口")
public void addUser() throws IOException, InterruptedException {
SqlSession session = DatabaseUtil.getSqlSession();
AddUserCase addUserCase = session.selectOne("addUserCase",1);
System.out.println("addUserCase"+addUserCase.toString());
System.out.println("addUserUrl"+TestConfig.addUserUrl);
/**
//下边的代码为写完接口的测试代码
String result = getResult(addUserCase);
//查询用户看是否添加成功
Thread.sleep(2000);
User user = session.selectOne("addUser",addUserCase);
System.out.println(user.toString());
//处理结果,就是判断返回结果是否符合预期
Assert.assertEquals(addUserCase.getExpected(),result);
*/
}
private String getResult(AddUserCase addUserCase) throws IOException {
//下边的代码为写完接口的测试代码
HttpPost post = new HttpPost(TestConfig.addUserUrl);
JSONObject param = new JSONObject();
param.put("userName",addUserCase.getUserName());
param.put("password",addUserCase.getPassword());
param.put("sex",addUserCase.getSex());
param.put("age",addUserCase.getAge());
param.put("permission",addUserCase.getPermission());
param.put("isDelete",addUserCase.getIsDelete());
//设置请求头信息 设置header
post.setHeader("content-type","application/json");
//将参数信息添加到方法中
StringEntity entity = new StringEntity(param.toString(),"utf-8");
post.setEntity(entity);
//设置cookies
TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
//声明一个对象来进行响应结果的存储
String result;
//执行post方法
HttpResponse response = TestConfig.defaultHttpClient.execute(post);
//获取响应结果
result = EntityUtils.toString(response.getEntity(),"utf-8");
System.out.println(result);
return result;
}
}
2、获取用户列表信息 GetUserInfoListTest
import com.tester.config.TestConfig;
import com.tester.model.GetUserListCase;
import com.tester.model.User;
import com.tester.utils.DatabaseUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.json.JSONArray;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.List;
public class GetUserInfoListTest {
@Test(dependsOnGroups="loginTrue",description = "获取性别为男的用户信息")
public void getUserListInfo() throws IOException, InterruptedException {
SqlSession session = DatabaseUtil.getSqlSession();
GetUserListCase getUserListCase = session.selectOne("getUserListCase",1);
System.out.println(getUserListCase.toString());
System.out.println(TestConfig.getUserListUrl);
/**
//下边为写完接口的代码 发送请求获取结果
JSONArray resultJson = getJsonResult(getUserListCase);
Thread.sleep(2000);
List<User> userList = session.selectList(getUserListCase.getExpected(),getUserListCase);
for(User u : userList){
System.out.println("list获取的user:"+u.toString());
}
JSONArray userListJson = new JSONArray(userList);
Assert.assertEquals(userListJson.length(),resultJson.length());
for(int i = 0;i<resultJson.length();i++){
JSONObject expect = (JSONObject) resultJson.get(i);
JSONObject actual = (JSONObject) userListJson.get(i);
Assert.assertEquals(expect.toString(), actual.toString());
}
*/
}
private JSONArray getJsonResult(GetUserListCase getUserListCase) throws IOException {
HttpPost post = new HttpPost(TestConfig.getUserListUrl);
JSONObject param = new JSONObject();
param.put("userName",getUserListCase.getUserName());
param.put("sex",getUserListCase.getSex());
param.put("age",getUserListCase.getAge());
//设置请求头信息 设置header
post.setHeader("content-type","application/json");
//将参数信息添加到方法中
StringEntity entity = new StringEntity(param.toString(),"utf-8");
post.setEntity(entity);
//设置cookies
TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
//声明一个对象来进行响应结果的存储
String result;
//执行post方法
HttpResponse response = TestConfig.defaultHttpClient.execute(post);
//获取响应结果
result = EntityUtils.toString(response.getEntity(),"utf-8");
JSONArray jsonArray = new JSONArray(result);
System.out.println("调用接口list result:"+result);
return jsonArray;
}
}
3、获取用户信息 GetUserInfoTest
import com.tester.config.TestConfig;
import com.tester.model.GetUserInfoCase;
import com.tester.model.User;
import com.tester.utils.DatabaseUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.json.JSONArray;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GetUserInfoTest {
@Test(dependsOnGroups="loginTrue",description = "获取userId为1的用户信息")
public void getUserInfo() throws IOException, InterruptedException {
SqlSession session = DatabaseUtil.getSqlSession();
GetUserInfoCase getUserInfoCase = session.selectOne("getUserInfoCase",1);
System.out.println(getUserInfoCase.toString());
System.out.println(TestConfig.getUserInfoUrl);
/**
//下边为写完接口的代码
JSONArray resultJson = getJsonResult(getUserInfoCase);
Thread.sleep(2000);
User user = session.selectOne(getUserInfoCase.getExpected(),getUserInfoCase);
System.out.println("自己查库获取用户信息:"+user.toString());
List userList = new ArrayList();
userList.add(user);
JSONArray jsonArray = new JSONArray(userList);
System.out.println("获取用户信息:"+jsonArray.toString());
System.out.println("调用接口获取用户信息:"+resultJson.toString());
Assert.assertEquals(jsonArray,resultJson);
*/
}
private JSONArray getJsonResult(GetUserInfoCase getUserInfoCase) throws IOException {
HttpPost post = new HttpPost(TestConfig.getUserInfoUrl);
JSONObject param = new JSONObject();
param.put("id",getUserInfoCase.getUserId());
//设置请求头信息 设置header
post.setHeader("content-type","application/json");
//将参数信息添加到方法中
StringEntity entity = new StringEntity(param.toString(),"utf-8");
post.setEntity(entity);
//设置cookies
TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
//声明一个对象来进行响应结果的存储
String result;
//执行post方法
HttpResponse response = TestConfig.defaultHttpClient.execute(post);
//获取响应结果
result = EntityUtils.toString(response.getEntity(),"utf-8");
System.out.println("调用接口result:"+result);
List resultList = Arrays.asList(result);
JSONArray array = new JSONArray(resultList);
System.out.println(array.toString());
return array;
}
}
4、登录测试
import com.tester.model.InterfaceName;
import com.tester.config.TestConfig;
import com.tester.model.LoginCase;
import com.tester.utils.ConfigFile;
import com.tester.utils.DatabaseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.IOException;
public class LoginTest {
@BeforeTest(groups = "loginTrue",description = "测试准备工作,获取HttpClient对象")
public void beforeTest(){
//声明http客户端
TestConfig.defaultHttpClient = new DefaultHttpClient();
TestConfig.getUserInfoUrl = ConfigFile.getUrl(InterfaceName.GETUSERINFO);
TestConfig.getUserListUrl = ConfigFile.getUrl(InterfaceName.GETUSERLIST);
TestConfig.loginUrl = ConfigFile.getUrl(InterfaceName.LOGIN);
TestConfig.updateUserInfoUrl = ConfigFile.getUrl(InterfaceName.UPDATEUSERINFO);
TestConfig.addUserUrl = ConfigFile.getUrl(InterfaceName.ADDUSERINFO);
}
@Test(groups = "loginTrue",description = "用户成功登陆接口")
public void loginTrue() throws IOException {
//查询数据
SqlSession session = DatabaseUtil.getSqlSession();
LoginCase loginCase = session.selectOne("loginCase",1);
//System.out.println("数据库数据:"+loginCase.toString());
//验证输出url
System.out.println("访问的url:"+TestConfig.loginUrl);
//发起http://localhost:8889/login请求,获取结果
String result = getResult(loginCase);
//处理结果,就是判断返回结果是否符合预期 getExpected=逾期结果 result=实际结果
Assert.assertEquals(loginCase.getExpected(),result);
System.out.println("预期结果:"+loginCase.getExpected()+"\n"+"实际结果:"+result);
}
@Test(description = "用户登陆失败接口")
public void loginFalse() throws IOException {
SqlSession session = DatabaseUtil.getSqlSession();
LoginCase loginCase = session.selectOne("loginCase",2);
System.out.println(loginCase.toString());
System.out.println(TestConfig.loginUrl);
/**
//下边的代码为写完接口的测试代码
String result = getResult(loginCase);
//处理结果,就是判断返回结果是否符合预期
Assert.assertEquals(loginCase.getExpected(),result);
*/
}
//登录用户
private String getResult(LoginCase loginCase) throws IOException {
//声明一个对象来进行响应结果的存储
String result;
//下边的代码为写完接口的测试代码
HttpPost post = new HttpPost(TestConfig.loginUrl);
JSONObject param = new JSONObject();
param.put("userName",loginCase.getUserName());
param.put("password",loginCase.getPassword());
//设置请求头信息 设置header
post.setHeader("content-type","application/json");
//将参数信息添加到方法中
StringEntity entity = new StringEntity(param.toString(),"utf-8");
post.setEntity(entity);
//执行post方法
HttpResponse response = TestConfig.defaultHttpClient.execute(post);
//获取响应结果
result = EntityUtils.toString(response.getEntity(),"utf-8");
//储存cookies信息
TestConfig.store = TestConfig.defaultHttpClient.getCookieStore();
return result;
}
}
5、更新用户信息
import com.tester.config.TestConfig;
import com.tester.model.UpdateUserInfoCase;
import com.tester.model.User;
import com.tester.utils.DatabaseUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
public class UpdateUserInfoTest {
@Test(dependsOnGroups = "loginTrue",description = "更改用户信息")
public void updateUserInfo() throws IOException, InterruptedException {
SqlSession session = DatabaseUtil.getSqlSession();
UpdateUserInfoCase updateUserInfoCase = session.selectOne("updateUserInfoCase",1);
System.out.println(updateUserInfoCase.toString());
System.out.println(TestConfig.updateUserInfoUrl);
/**
//下边为写完接口的代码
int result = getResult(updateUserInfoCase);
//获取更新后的结果
Thread.sleep(2000);
User user = session.selectOne(updateUserInfoCase.getExpected(),updateUserInfoCase);
System.out.println(user.toString());
Assert.assertNotNull(user);
Assert.assertNotNull(result);
*/
}
@Test(dependsOnGroups = "loginTrue",description = "删除用户")
public void deleteUser() throws IOException, InterruptedException {
SqlSession session = DatabaseUtil.getSqlSession();
UpdateUserInfoCase updateUserInfoCase = session.selectOne("updateUserInfoCase",2);
System.out.println(updateUserInfoCase.toString());
System.out.println(TestConfig.updateUserInfoUrl);
/**
//下边为写完接口的代码
int result = getResult(updateUserInfoCase);
Thread.sleep(2000);
User user = session.selectOne(updateUserInfoCase.getExpected(),updateUserInfoCase);
System.out.println(user.toString());
Assert.assertNotNull(user);
Assert.assertNotNull(result);
*/
}
private int getResult(UpdateUserInfoCase updateUserInfoCase) throws IOException {
HttpPost post = new HttpPost(TestConfig.updateUserInfoUrl);
JSONObject param = new JSONObject();
param.put("id",updateUserInfoCase.getUserId());
param.put("userName",updateUserInfoCase.getUserName());
param.put("sex",updateUserInfoCase.getSex());
param.put("age",updateUserInfoCase.getAge());
param.put("permission",updateUserInfoCase.getPermission());
param.put("isDelete",updateUserInfoCase.getIsDelete());
//设置请求头信息 设置header
post.setHeader("content-type","application/json");
//将参数信息添加到方法中
StringEntity entity = new StringEntity(param.toString(),"utf-8");
post.setEntity(entity);
//设置cookies
TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
//声明一个对象来进行响应结果的存储
String result;
//执行post方法
HttpResponse response = TestConfig.defaultHttpClient.execute(post);
//获取响应结果
result = EntityUtils.toString(response.getEntity(),"utf-8");
System.out.println(result);
return Integer.parseInt(result);
}
}
config类
1、报告配置
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();
}
}
2、用户路径配置
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类
import lombok.Data;
@Data
public class AddUserCase {
private int id;
private String userName;
private String password;
private String sex;
private String age;
private String permission;
private String isDelete;
private String expected;
}
@Data
public class GetUserInfoCase {
private int id;
private int userId;
private String expected;
}
@Data
public class GetUserListCase {
private String userName;
private String age;
private String sex;
private String expected;
}
public enum InterfaceName {
GETUSERLIST,
LOGIN,
UPDATEUSERINFO,
GETUSERINFO,
ADDUSERINFO
}
@Data
public class LoginCase {
private int id;
private String userName;
private String password;
private String expected;
}
@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;
}
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+"}"
);
}
}
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;
}
}
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;
}
}
模板–页面模板内容自己可以去百度找
package com.tester.utils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.testng.*;
import org.testng.xml.XmlSuite;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
public class TestReport implements IReporter {
private long currentTime = System.currentTimeMillis();
private SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
private Date date = new Date(currentTime);
private String reportdate = formatter.format(date);
// 定义生成测试报告的路径和文件名,为兼容Windows和Linux此处使用File.separator代替分隔符
private String path = System.getProperty("user.dir")+File.separator+reportdate+".html";
// 定义html样式模板所在路径
private String templatePath = System.getProperty("user.dir")+File.separator+"template";
private int testsPass = 0;
private int testsFail = 0;
private int testsSkip = 0;
private String beginTime;
private long totalTime;
private String name = "PaaS平台自动化测试";
/**
public TestReport(){
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
Date date = new Date(currentTime);
name = formatter.format(date);
}
public TestReport(String name){
this.name = name;
if(this.name==null){
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
Date date = new Date(currentTime);
this.name = formatter.format(date);
}
}
*/
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
List<ITestResult> list = new ArrayList<ITestResult>();
for (ISuite suite : suites) {
Map<String, ISuiteResult> suiteResults = suite.getResults();
for (ISuiteResult suiteResult : suiteResults.values()) {
ITestContext testContext = suiteResult.getTestContext();
IResultMap passedTests = testContext.getPassedTests();
testsPass = testsPass + passedTests.size();
IResultMap failedTests = testContext.getFailedTests();
testsFail = testsFail + failedTests.size();
IResultMap skippedTests = testContext.getSkippedTests();
testsSkip = testsSkip + skippedTests.size();
IResultMap failedConfig = testContext.getFailedConfigurations();
list.addAll(this.listTestResult(passedTests));
list.addAll(this.listTestResult(failedTests));
list.addAll(this.listTestResult(skippedTests));
list.addAll(this.listTestResult(failedConfig));
}
}
this.sort(list);
this.outputResult(list);
}
private ArrayList<ITestResult> listTestResult(IResultMap resultMap) {
Set<ITestResult> results = resultMap.getAllResults();
return new ArrayList<ITestResult>(results);
}
private void sort(List<ITestResult> list) {
Collections.sort(list, new Comparator<ITestResult>() {
@Override
public int compare(ITestResult r1, ITestResult r2) {
if (r1.getStartMillis() > r2.getStartMillis()) {
return 1;
} else {
return -1;
}
}
});
}
private void outputResult(List<ITestResult> list) {
try {
List<ReportInfo> listInfo = new ArrayList<ReportInfo>();
int index = 0;
for (ITestResult result : list) {
String tn = result.getTestContext().getCurrentXmlTest().getParameter("testCase");
if(index==0){
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
beginTime = formatter.format(new Date(result.getStartMillis()));
index++;
}
long spendTime = result.getEndMillis() - result.getStartMillis();
totalTime += spendTime;
String status = this.getStatus(result.getStatus());
List<String> log = Reporter.getOutput(result);
for (int i = 0; i < log.size(); i++) {
log.set(i, log.get(i).replaceAll("\"", "\\\\\""));
}
Throwable throwable = result.getThrowable();
if(throwable!=null){
log.add(throwable.toString().replaceAll("\"", "\\\\\""));
StackTraceElement[] st = throwable.getStackTrace();
for (StackTraceElement stackTraceElement : st) {
log.add((" " + stackTraceElement).replaceAll("\"", "\\\\\""));
}
}
ReportInfo info = new ReportInfo();
info.setName(tn);
info.setSpendTime(spendTime+"ms");
info.setStatus(status);
info.setClassName(result.getInstanceName());
info.setMethodName(result.getName());
info.setDescription(result.getMethod().getDescription());
info.setLog(log);
listInfo.add(info);
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("testName", name);
result.put("testPass", testsPass);
result.put("testFail", testsFail);
result.put("testSkip", testsSkip);
result.put("testAll", testsPass+testsFail+testsSkip);
result.put("beginTime", beginTime);
result.put("totalTime", totalTime+"ms");
result.put("testResult", listInfo);
Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
String template = this.read(templatePath);
BufferedWriter output = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(new File(path)),"UTF-8"));
template = template.replaceFirst("\\$\\{resultData\\}", Matcher.quoteReplacement(gson.toJson(result)));
output.write(template);
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private String getStatus(int status) {
String statusString = null;
switch (status) {
case 1:
statusString = "成功";
break;
case 2:
statusString = "失败";
break;
case 3:
statusString = "跳过";
break;
default:
break;
}
return statusString;
}
public static class ReportInfo {
private String name;
private String className;
private String methodName;
private String description;
private String spendTime;
private String status;
private List<String> log;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getSpendTime() {
return spendTime;
}
public void setSpendTime(String spendTime) {
this.spendTime = spendTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<String> getLog() {
return log;
}
public void setLog(List<String> log) {
this.log = log;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
private String read(String path) {
File file = new File(path);
InputStream is = null;
StringBuffer sb = new StringBuffer();
try {
is = new FileInputStream(file);
int index = 0;
byte[] b = new byte[1024];
while ((index = is.read(b)) != -1) {
sb.append(new String(b, 0, index));
}
return sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
配置配置类
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>
spring boot全局配置
test.url=http://localhost:8888
#登陆接口uri
login.uri=/login
#更新用户信息接口uri
updateUserInfo.uri=/updateUserInfo
#获取用户列表接口uri
getUserList.uri=/getUserListInfo
#获取用户信息接口uri
getUserInfo.uri=/getUserInfo
#添加用户接口uri
addUser.uri=/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://127.0.0.1:3306/course"/>
<!-- 数据库用户... -->
<property name="username" value="root"/>
<!-- 数据库密码... -->
<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>
测试
1、前提条件
第一步:首先mock数据
[
{
"description":"登陆接口,成功后返回cookies",
"request":{
"uri":"/login",
"method":"post",
"json":{
"userName":"abc",
"password":"123"
}
},
"response":{
"cookies":{
"login":"true"
},
"text":"true"
}
},
{
"description":"获取用户信息",
"request":{
"uri":"/getUserInfo",
"method":"post",
"json":{
"userId":"1"
},
"cookies":{
"login":"true"
}
},
"response":{
"json":{
"id":"1",
"userName":"zhangsan",
"password":"123456",
"age":"20",
"sex":"0",
"permission":"0",
"isDelete":"0"
}
}
},
{
"description":"获取用户信息接口",
"request":{
"uri":"/getUserListInfo",
"method":"post",
"json":{
"sex":"0"
},
"cookies":{
"login":"true"
}
},
"response":{
"json":[
{
"id":"1",
"userName":"zhangsan",
"password":"123456",
"age":"20",
"sex":"0",
"permission":"0",
"isDelete":"0"
},
{
"id":"3",
"userName":"wangwu",
"password":"123456",
"age":"30",
"sex":"0",
"permission":"1",
"isDelete":"0"
},{
"id":"5",
"userName":"zhang1",
"password":"123",
"age":"20",
"sex":"0",
"permission":"0",
"isDelete":"0"
}
]
}
},
{
"description":"增加用户接口",
"request":{
"uri":"/addUser",
"method":"post",
"json":{
"userName":"zhao9",
"password":"zhaozhao",
"sex":"0",
"age":"35",
"permission":"1",
"isDelete":"0"
},
"cookies":{
"login":"true"
}
},
"response":{
"text":"true"
}
},
{
"description":"增加用户接口",
"request":{
"uri":"/updateUserInfo",
"method":"post",
"json":{
"userId":"2",
"userName":"hahahaha"
},
"cookies":{
"login":"true"
}
},
"response":{
"text":"true"
}
},
{
"description":"删除用户接口",
"request":{
"uri":"/deleteUser",
"method":"post",
"json":{
"userId":"8"
},
"cookies":{
"login":"true"
}
},
"response":{
"text":"true"
}
}
]
第二步:启动服务
java -jar ./moco-runner-0.11.0-standalone.jar http -p 8888 -c userManager.json
启动服务注意事项
- 一定的在moco-runner-0.11.0-standalone.jar包下启动,否则找不到包
第三步::使用postman测试mock服务是否可用
第四步:数据的准备 准备用户名等于 abc的数(用于登录结果的验证)
2、已登录成功案例测试为例:
自己在测试中值得的问题
- java -jar ./moco-runner-0.11.0-standalone.jar http -p 8888 -c userManager.json 启动的端口要和application.properties文件中配置的一样
- 在getResult()方法中,塞值一定要和mock中请求参数的字段一样
- 请求的方式要设置好,是已JSON还是key-value的方式
- 在查询数据库的时候,model定义的字段民要和数据库一致