【七:(测试用例)spring boot+testng+xml+mock实现用例管理+数据校验】
目录
- 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());//设置请求头信息 设置headerpost.setHeader("content-type","application/json");//将参数信息添加到方法中StringEntity entity = new StringEntity(param.toString(),"utf-8");post.setEntity(entity);//设置cookiesTestConfig.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());//设置请求头信息 设置headerpost.setHeader("content-type","application/json");//将参数信息添加到方法中StringEntity entity = new StringEntity(param.toString(),"utf-8");post.setEntity(entity);//设置cookiesTestConfig.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());//设置请求头信息 设置headerpost.setHeader("content-type","application/json");//将参数信息添加到方法中StringEntity entity = new StringEntity(param.toString(),"utf-8");post.setEntity(entity);//设置cookiesTestConfig.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());//验证输出urlSystem.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());//设置请求头信息 设置headerpost.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());//设置请求头信息 设置headerpost.setHeader("content-type","application/json");//将参数信息添加到方法中StringEntity entity = new StringEntity(param.toString(),"utf-8");post.setEntity(entity);//设置cookiesTestConfig.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;@Overridepublic 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>() {@Overridepublic 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组合代替报告中的namefor(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 {//登陆接口uripublic static String loginUrl;//更新用户信息接口uripublic static String updateUserInfoUrl;//获取用户列表接口uripublic static String getUserListUrl;//获取用户信息接口uripublic 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;@Overridepublic 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);}}*/@Overridepublic 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>() {@Overridepublic 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 loginCasewhere 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 whereuserName=#{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 whereid=#{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定义的字段民要和数据库一致
2.1、直接在用例里面测试验证是否能用
2.2、在xml测试套件是否可用
相关文章:

【七:(测试用例)spring boot+testng+xml+mock实现用例管理+数据校验】
目录 1、目录结构的相关类cases类1、添加用户 AddUserTest2、获取用户列表信息 GetUserInfoListTest3、获取用户信息 GetUserInfoTest4、登录测试5、更新用户信息 config类1、报告配置2、用户路径配置 model类utils类 配置配置类SQLMapper.xmlspring boot全局配置databaseConfi…...

哪些数据应该先治理
在我们提供的数据中,哪些是真正需要优先治理的呢?这是任何数据治理项目开始之前都需要解决的问题。正确地确定了数据治理的优先级,不仅可以帮助我们将有限的资源用在刀刃上,更能实现数据治理的最大价值。下面数聚就深度为企业管理…...

No module ‘xformers‘. Proceeding without it.
一、背景: 运行提示 No module xformers. Proceeding without it. 二、分析 1、xformers是SD的加速模块,没有他可以继续运行,可以正常生成图片。只是xformers可以帮助提升图片的生成速度。 2、安装完SD后,启动出现xformers未安…...

Stable Diffusion WebUI报错RuntimeError: Torch is not able to use GPU解决办法
新手在安装玩Stable Diffusion WebUI之后会遇到各种问题, 接下来会慢慢和你讲解如何解决这些问题。 在我们打开Stable Diffusion WebUI时会报错如下: RuntimeError: Torch is not able to use GPU;add --skip-torch-cuda-test to COMMANDL…...

金融信息化研究所与YashanDB等单位启动金融多主数据库应用行动计划
10月13日,2023金融业 数据库技术大会在京成功召开。会上,金融信息化研究所与崖山数据库YashanDB、阿里巴巴、奥星贝斯、达梦、南大通用、华为、天翼云、万里数据库、优炫数据库共同启动金融多主数据库应用行动计划,并成立金融多主数据库应用…...

工具篇之Axure RP 10的使用
引言 最近在学习原型图,针对画原型图的工具,反复对比墨刀、Axure、xiaopiu后,最终选择Axure。 接下来,我便从Axure RP 10的下载、安装、中文字体、授权等几个方面,来介绍Axure。 一、背景 Axure是一款强大的原型设计…...

C#选择排序(Selection Sort)算法
选择排序(Selection Sort)原理介绍 选择排序(Selection Sort)是一种简单的排序算法,其实现原理如下: 遍历待排序数组,从第一个元素开始。 假设当前遍历的元素为最小值,将其索引保存…...

【Mysql】InnoDB数据页结构(五)
概述 页是InnoDB存储引擎管理存储空间的基本单位,一个页的大小默认是16KB 。InnoDB 为了不同的目的而设计了许多种不同类型的页 ,比如存放记录的索引页,存放表空间头部信息的页,存放 Insert Buffer信息的页,存放 INOD…...

Golang中的type关键字
type关键字在Go语言中有五种用法: 定义结构体定义接口类型别名类型定义类型开关其中,定义结构体和定义接口是Go语言中常用的类型定义方式,类型别名和类型定义则是为了方便程序员使用而设计的,而类型开关则是Go语言中比较特殊的一种类型定义方式。 定义结构体 结构体是由一…...

网站管家机器人在为企业获客方面起什么作用?
随着科技的不断进步和人们对便捷服务的需求增加,网站管家机器人成为了现代企业获客的重要工具。作为一种基于人工智能技术的在线助手,网站管家机器人可以与访问企业网站的用户进行智能对话,并提供即时的帮助和解答。 网站管家机器人在为企业获…...

竞赛选题 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv
文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 *…...

零基础学习HTML5
1. 使用软件 vscode 谷歌浏览器 vscode下载地址:https://code.visualstudio.com/ 谷歌可以使用360软件管家安装 2. 安装插件 在vscode中安装插件:open in browser,点击Extensions后搜索对应插件名然后点击安装Install 安装完成后可在htm…...

Jenkins 部署 Maven项目很慢怎么办?
Jenkins 部署 Maven项目很慢怎么办? 答案是:使用阿里云的Maven仓库 <mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共仓库</name><url>https://maven.aliyun.com/repository/pub…...

关于刷题时使用数组的小注意事项
💯 博客内容:关于刷题时使用数组的小技巧 😀 作 者:陈大大陈 🚀 个人简介:一个正在努力学技术的准前端,专注基础和实战分享 ,欢迎私信! 💖 欢迎大家&#…...

【MySQL】面试题
引言 :MySQL面试题及答案 【最新版】 目录 1、NOW()和CURRENT_DATE()有什么区别?2、CHAR和VARCHAR的区别?3、主键索引与唯一索引的区别4、MySQL中有哪些不同的表格?5、SQL的生命周期…...

Pytorch训练深度强化学习时CPU内存占用一直在快速增加
最近在用MATD3算法解决多机器人任务,但是在训练过程中,CPU内存一直在增加(注意,不是GPU显存)。我很头疼,以为是算法代码出了问题,导致了内存泄漏,折腾了1天也没解决。后来用memory_p…...

git第一次推送出现推送被拒绝
前言 git 第一次推送出现以下错误 ! [rejected] master -> master (fetch first) error: failed to push some refs to ‘https://gitee.com/fengshangyunwang/iot-front-end.git’ hint: Updates were rejected because the remote contains work that you do hint: not …...
CRC16计算FC(博途SCL语言)
CRC8的计算FC,相关链接请查看下面文章链接: 博途SCL CRC8 计算FC(计算法)_博途怎么计算crc_RXXW_Dor的博客-CSDN博客关于CRC8的计算网上有很多资料和C代码,这里不在叙述,这里主要记录西门子的博途SCL完成CRC8的计算过程, CRC校验算法,说白了,就是把需要校验的数据与多项式…...

setsockopt()函数的用法
setsockopt() 函数是一个用于设置套接字选项的函数,通常在网络编程中使用。它用于配置套接字的各种参数和选项,以满足特定的需求。setsockopt() 函数的作用是设置指定套接字选项的值。 setsockopt() 函数的一般用法: int setsockopt(int soc…...

【AOP系列】6.缓存处理
在Java中,我们可以使用Spring AOP(面向切面编程)和自定义注解来做缓存处理。以下是一个简单的示例: 首先,我们创建一个自定义注解,用于标记需要进行缓存处理的方法: import java.lang.annotat…...

云函数cron-parser解析时区问题
1、问题 云函数部署后cron-parser解析0点会变成8点 考虑可能是时区的问题 然后看文档发现果然有问题,云函数环境是utc0 2、解决 看了半天cron-parser文档发现 Using Date as an input can be problematic specially when using the tz option. The issue bein…...

Android11修改自动允许连接到建议的WLAN网络
客户的app需要连接指定的wifi,但是会提示下面的对话框(是否允许系统连接到建议的WLAN网络?): 客户需求:不提示这个对话框自动允许。 根据字符串定位到frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiNetworkSuggestionsManager.java 中的privat…...

基于Qt HTTP应用程序项目案例
文章目录 主项目入口项目子头文件httpwindow.hhttpwindow.h源文件httpwindow.cppui文件效果演示主项目入口 main函数创建对象空间,确认窗口的大小和坐标。 #include <QApplication> #include <QDir> #include...

OpenGL —— 2.7、绘制多个自旋转的贴图正方体(附源码,glfw+glad)
源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库,该库只有一个头文件。 具体代码: vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix; …...

linux之perf(8)annotate标注
Linux之perf(8)annotate标注 Author:Onceday Date:2023年10月12日 漫漫长路,才刚刚开始… 注:该文档内容采用了GPT4.0生成的回答,部分文本准确率可能存在问题。 参考文档: Tutorial - Perf Wiki (kernel.org)perf…...

【广州华锐互动】VR建筑安全培训体验为建筑行业人才培养提供有力支持
随着建筑行业的快速发展,建筑施工安全问题日益受到广泛关注。然而,传统的安全培训方式往往缺乏实践性和真实性,难以让员工真正掌握安全操作技能。近年来,虚拟现实(VR)技术的广泛应用为建筑施工安全培训提供了新的机遇。 虚拟现实技…...

【Javascript保姆级教程】运算符
文章目录 前言一、运算符是什么二、赋值运算符2.1 如何使用赋值运算符2.2 示例代码12.3 示例代码2 三、自增运算符3.1 运算符3.2 示例代码13.3 示例代码2 四、比较运算符4.1 常见的运算符4.2 如何使用4.3 示例代码14.4 示例代码2 五、逻辑运算符逻辑运算符列举 六、运算符优先级…...

图论与网络优化
2.概念与计算 2.1 图的定义 2.1.1 定义 图(graph) G G G 是一个有序的三元组,记作 G < V ( G ) , E ( G ) , ψ ( G ) > G<V(G),E(G),\psi (G)> G<V(G),E(G),ψ(G)>。 V ( G ) V(G) V(G) 是顶点集。 E ( G ) E(G) E(G) 是边集。 ψ ( G ) \…...

【论文复现】基于多模态深度学习方法的单细胞多组学数据聚类(【生物信息学】实验二:多组学数据融合:scMDC)
目录 一、实验介绍 1. 论文:基于多模态深度学习方法的单细胞多组学数据聚类 Abstract 2. Github链接 二、实验环境 0. 作者要求 1. 环境复现 实验一 实验二(本实验) 2. 库版本介绍 实验一 实验二 3. IDE 三、实验内容 1. 用法…...

mysql按指定字符截取
1、使用SUBSTRING函数进行截取 语法:str是要截取的字符串,pos是起始位置,len是要截取的长度 SUBSTRING(str, pos, len)例子 SELECT SUBSTRING(Hello, World!, 1, 5);返回"Hello"。其中,起始位置为1,截取的…...