【七:(测试用例)spring boot+testng+xml+mock实现用例管理+数据校验】

news2024/11/19 20:20:18

目录

  • 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测试套件是否可用

image.png

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;
    }
}

模板–页面模板内容自己可以去百度找
image.png

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服务是否可用

image.png

第四步:数据的准备 准备用户名等于 abc的数(用于登录结果的验证)

image.png

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、直接在用例里面测试验证是否能用

image.png

2.2、在xml测试套件是否可用

image.png
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1112345.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卷王问卷考试系统SurveyKing,开源调查问卷和考试系统源码

卷王问卷考试系统/SurveyKing是一个功能最强大的开源调查问卷和考试系统&#xff0c;可以快速部署&#xff0c;并适用于各行业。该系统提供了在线表单设计、数据收集、统计和分析等功能&#xff0c;支持20多种题型&#xff0c;多种创建问卷方式和多种问卷设置。 无论您是需要进…

解决Github Markdown图片显示残缺的问题

title: 解决Github Markdown图片显示残缺的问题 tags: 个人成长 categories:杂谈 在Github存放Markdown文档&#xff0c;如果图片没有存放在Github服务器上&#xff0c;github会尝试生成Github图片缓存&#xff0c;使用Github图片缓存&#xff0c;进行实际的展示。但比较蛋疼的…

在ROS中将点云(PointCloud2)生成Octomap,rviz可视化显示

一个python文件作为publisher&#xff0c;发布点云数据。一个C项目接收点云数据&#xff0c;引用octomap库&#xff0c;将点云生成octomap的tree&#xff0c;在将tree通过topic发布出去&#xff0c;rviz订阅octomap tree的topic进行可视化显示。 首先创建一个python的点云发布…

使用MFC创建一个SaleSystem

目录 1、项目的创建&#xff1a; 2、项目的配置&#xff1a; 3、设置窗口属性&#xff1a; &#xff08;1&#xff09;、设置图标 1&#xff09;、添加导入资源 2&#xff09;、代码初始化图标 &#xff08;2&#xff09;、设置标题 &#xff08;3&#xff09;、设置窗口…

【文献copilot】调用文心一言api对论文逐段总结

文献copilot&#xff1a;调用文心一言api对论文逐段总结 当我读文献的时候&#xff0c;感觉读得太慢了&#xff0c;看翻译软件翻译的又觉得翻译的不好。于是我就写了个程序辅助我读文献&#xff0c;它可以逐段总结&#xff0c;输出格式是&#xff1a;原文一句话总结分段总结&a…

Kafka与MySQL的组合使用

根据上面给出的student表&#xff0c;编写Python程序完成如下操作&#xff1a; &#xff08;1&#xff09;读取student表的数据内容&#xff0c;将其转为JSON格式&#xff0c;发送给Kafka&#xff1b; 创建Student表的SQL语句如下&#xff1a; create table student( sno ch…

基于深度学习网络的蔬菜水果种类识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1数据集准备 4.2构建深度学习模型 4.3模型训练 4.4模型评估 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 clc; clear; close all; wa…

【C++】C++学习(模板+排序+测时)

本文主要记录使用模板函数来编写排序算法&#xff0c;并计算运行时间。 模板函数&#xff08;Template Function&#xff09;是一种通用函数&#xff0c;可以在其定义时不指定具体的参数类型&#xff0c;在调用时再根据需要指定具体类型。模板函数可以接受不同类型的参数&…

057:mapboxGL中layout,paint等属性的函数表达说明

第057个 点击查看专栏目录 本篇文章是mapbox的layer中layout,paint等属性的函数表达 mapbox中 Function 是什么 函数 Function 可以作为其 layout布局类属性和 paint 绘制类属性的属性值。在使用 Function 作为属性值时,实际上是一个对象。 layers的3种函数类型 Function …

error: unable to read askpass response from

报错信息 解决方法&#xff1a; 中文&#xff1a;文件-->设置-->版本控制-->Git-->勾选使用凭证帮助程序 英文&#xff1a;File -> Settings -> Version Control -> Git / Check "User credential Helper" 因为我的webstrom是中文版的&#…

Simulink 最基础教程(四)模型参数与全局变量

4.1模型参数 上面介绍常用模块的时候&#xff0c;都是找到模块&#xff0c;双击模块&#xff0c;设置参数。这些参数都是模块参数。与之相对的&#xff0c;是模型参数。一些说明&#xff1a; 1&#xff09;模型参数和模块参数并不是隶属关系&#xff0c;而是配合关系。当模型参…

起重机控制电路接线 - 基础与进阶(修订中...)

1.基础篇 起重机电气接线 - 理论与实践 - 知乎1.现场配电箱这是一台10吨电动葫芦的电器箱。你能看出这个起重机用到了几个电机吗&#xff1f;先看空开和继电器。 电机为了控制正反转&#xff0c;一般每个电机需要用到两个继电器。这上面有7个继电器&#xff0c;所以&#xff0…

数字图像处理实验记录四(图像的空间域增强-平滑处理)

前言&#xff1a;要是是实验报告赶工的话&#xff0c;建议总结上网抄&#xff0c;或者重构我的总结&#xff0c;仅供学习参考&#xff0c;不要照抄 文章目录 一、基础知识1&#xff0c;噪声2&#xff0c;椒盐噪声3&#xff0c;高斯噪声4&#xff0c;滤波器5&#xff0c;均值滤…

[云原生1.] Docker容器的简单介绍和基本管理

1. Docker容器的基本概述 1.1 简介 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级…

Unity之ShaderGraph如何实现无贴图水球效果

前言 我们今天来实现一个无贴图水球效果&#xff0c;如下图所示&#xff1a; 主要节点 UVSplit&#xff1a;可以获得UV在RGB三个颜色分别的分量 Remap&#xff1a;重映射节点 基于输入 In 值在输入In Min Max的 x 和 y 分量之间的线性插值&#xff0c;返回输入Out Min Max…

爬虫三大库

Requests库安装 Requests库的作用是请求网站获得网页数据 在pycharm中安装方式如下&#xff1a; 选择settings 选择Project Interpreter&#xff0c;单击号添加第三方库 BeautifulSoup库按同样方式安装。 Requests库 pycharm返回结果为<Response [200]>,说明请求网址成…

简单秒表设计仿真verilog跑表,源码/视频

名称&#xff1a;简单秒表设计仿真 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 秒表显示最低计时为10ms&#xff0c;最大为59:99&#xff0c;超出返回00&#xff1a;00 具有复位、启动、暂停三个按键 四个数码管分别显示4个时间数字。 演示…

了解 Elasticsearch 自动生成的文档 _id:重复是一个问题吗?

Elasticsearch 中自动生成的文档 ID 当你在未指定 ID 的情况下对文档建立索引时&#xff0c;Elasticsearch 会自动为该文档生成唯一的 ID。 该 ID 是 Base64 编码的 UUID&#xff0c;由多个部分组成&#xff0c;每个部分都有特定的用途。 ID 生成过程针对索引速度和存储效率进…

互联网Java工程师面试题·Java 总结篇·第九弹

目录 75、阐述 JDBC 操作数据库的步骤。 76、Statement 和 PreparedStatement 有什么区别&#xff1f;哪个性 能更好&#xff1f; 77、使用 JDBC 操作数据库时&#xff0c;如何提升读取数据的性能&#xff1f;如何提升更新数据的性能&#xff1f; 78、在进行数据库编程时&a…

git 查看本地秘钥

第一步&#xff1a; 1&#xff0c;打开终端或者命令行窗口&#xff0c;输入一下命令&#xff1a; cd ~/.ssh进入ssh目录 2&#xff0c;查看该目录下的所有文件&#xff0c;输入以下命令: ls -al该命令将显示ssh目录下的所有文件&#xff0c;包括秘钥文件和配置文件,如果不存…