【七:(测试用例)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…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...