TestNG+HttpClient - the first project

1, Foreword

The previous articles talked about the basic use of testng and httpclient. After mastering these knowledge, you can carry out new projects, because only in the project will you encounter various new problems and promote yourself to learn more. This article will mainly describe the project in the form of post code, and there will not be too many text descriptions.

I have done a project with httprunner before. The use case design principle of this project is the same as that of httprunner (if you are interested, you can turn to my previous blog). It is probably to extract public things (such as login and environment), and then a menu and a script file. The file can contain multiple use cases.

Knowledge involved in this article:

  • Encapsulation of post, get and put requests of HttpClient
  • java instance, member variable, local variable
  • jsonpath extracts the response field (using Ali's fastjson)
  • Extracting response fields from regular expressions
  • testng run

Main process of project use case: login > New Order   > Delivery after data entry  

2, Project structure display

 

  3, Detailed example of project

1. HttpClientUtils.java under the common package

Note: it encapsulates the httpclient request and the environment address of the business system

Usage: the business system can call the encapsulated code to directly send httpclient requests to reduce code redundancy

package com.tech.common;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

/**
 * @author One plus one
 * @date 2021-11-18
 * HttpClient Tool class
 */

public class HttpClientUtils {
    /**
     * Define host, environment address
     * @return
     */
    public static String  host(){
        String host = "https://xxx-api.xxx.cn";
        return host;
    }

    /**
     * get request
     * @param url
     * @param token
     * @return
     */
    public static String doGet(String url,String token) throws IOException{
        try {
            //Create browser objects
            HttpClient httpClient = HttpClients.createDefault();
            //establish get Request object
            HttpGet httpGet = new HttpGet(url);
            //add to get Request header
            httpGet.setHeader("Accept","application/json");
            httpGet.setHeader("Content-Type","application/json");
            httpGet.setHeader("Token",token);
            //implement get request
            HttpResponse response = httpClient.execute(httpGet);
            //The request was sent successfully and received a response
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                //Read the information returned by the server json character string
                String jsonString = EntityUtils.toString(response.getEntity());
                //take json character string return
                return jsonString;
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * post Request (parameters for requesting json format)
     * @param url
     * @param params
     * @param token
     * @return
     */
    public static String doPost(String url,String params,String token) throws IOException{
        
        //Create browser objects
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //establish httpPost object
        HttpPost httpPost = new HttpPost(url);
        //add to httpPost Request header for
        httpPost.setHeader("Accept","application/json");
        httpPost.setHeader("Content-Type","application/json");
        httpPost.setHeader("Token",token);
        //Add request parameters to Entity
        StringEntity entity = new StringEntity(params,"UTF-8");
        httpPost.setEntity(entity);
        //Define a response variable with an initial value of null
        CloseableHttpResponse response = null;

        try {
            //Execute the request and receive the returned response value with a variable
            response = httpClient.execute(httpPost);
            //Gets the status of the response
            StatusLine status = response.getStatusLine();
            //Gets the of the response code
            int state = status.getStatusCode();
            //SC_OK=200
            if(state == HttpStatus.SC_OK){
                HttpEntity responseEntity = response.getEntity();
                String jsonString = EntityUtils.toString(responseEntity);
                return jsonString;
            }
            else {
                System.out.println(("Return error"));
            }
        }
        finally {
            if(response!=null){
                try {
                    response.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            try {
                httpClient.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * put Request (parameters for requesting json format)
     * @param url
     * @param params
     * @param token
     * @return
     */
    public static String doPut(String url,String params,String token) throws IOException{

        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPut httpPut = new HttpPut(url);
        httpPut.setHeader("Accept","application/json");
        httpPut.setHeader("Content-Type","application/json");
        httpPut.setHeader("Token",token);
        StringEntity entity = new StringEntity(params,"UTF-8");
        httpPut.setEntity(entity);
        CloseableHttpResponse response = null;

        try {
            response = httpClient.execute(httpPut);
            StatusLine status = response.getStatusLine();
            int state = status.getStatusCode();
            if(state == HttpStatus.SC_OK){
                HttpEntity responseEntity = response.getEntity();
                String jsonString = EntityUtils.toString(responseEntity);
                return jsonString;
            }
            else {
                System.out.println(("Return error"));
            }
        }
        finally {
            if(response!=null){
                try {
                    response.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            try {
                httpClient.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return null;
    }
}

  2. Config.java under testng package

Description: use case of login system A

Usage: [login] is mainly used to obtain the dynamically generated token after successful login. The dynamic token needs to be used in the interface request of the business system

package com.tech.testng;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.testng.annotations.Test;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Config {
    //Defines the member variables of the class
    String code = "";//generate token Interface required code
    String Token="";
    String host = "https://qa-xxx-api.xxx.cn";//Login environment domain name (login system and business system are two different systems, so another one is redefined here host)
    String loginFromServer = "https://xxx.cn";//Point to the domain name of the corresponding system environment
    String username = "Li Bai";//Login account
    String password = "123456";//Login password
    
    @Test(description ="Login interface")
    public void Login() throws IOException {
        String url = host+"/saas/auth/login";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36");
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

        List<BasicNameValuePair> param = new ArrayList<>(4);
        param.add(new BasicNameValuePair("loginFromServer", loginFromServer));
        param.add(new BasicNameValuePair("username", username));
        param.add(new BasicNameValuePair("password", password));

        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(param, StandardCharsets.UTF_8);
        httpPost.setEntity(formEntity);
        CloseableHttpResponse response = httpClient.execute(httpPost);//Execute request
        //System.out.println("The response status is:" + response.getStatusLine());
        String body = EntityUtils.toString(response.getEntity());//Get response content
        System.out.println("Login The response contents are:" + body);

        JSONObject jsonObject = JSON.parseObject(body);//convert to json format
        String data = jsonObject.getString("data");//Get data value       //Splice double quotes: "\""+    +"\""

        Pattern pattern = Pattern.compile("code=(.*)");//Regular expression extraction code
        Matcher matcher = pattern.matcher(data);

        if(matcher.find()) {
            code = matcher.group(1);
            System.out.println("Extracted code Is:" + code);
        }
    }

    @Test(description = "generate token Interface",dependsOnMethods = {"Login"})
    public String exchangeToken() throws IOException {
        String url = host+"/saas/auth/exchangeToken";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36");
        httpPost.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");

        List<BasicNameValuePair> param = new ArrayList<>(1);
        param.add(new BasicNameValuePair("code",code));
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(param, StandardCharsets.UTF_8);
        httpPost.setEntity(formEntity);//Execute request

        CloseableHttpResponse response = httpClient.execute(httpPost);//Get response content
        HttpEntity res = response.getEntity();
        String message = EntityUtils.toString(res);
        //String body = EntityUtils.toString(response.getEntity());
        //System.out.println("exchangeToken The response contents are:"+body);
        System.out.println("token response"+message);

        JSONObject jsonObject = JSON.parseObject(message);//convert to json format
        JSONObject jsonObject1 = jsonObject.getJSONObject("data");//Get data value
        Token = jsonObject1.getString("ssoToken");//obtain data In the object ssoToken,And assigned to Token
        System.out.println("exchangeToken Generated Token Is:"+Token);

        //return Token Reference for other use cases
        return Token;
    }

}

3. Demand.java under the demand package

Description: use case of business system B

Usage: [new order]

package com.tech.demand;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tech.common.HttpClientUtils;
import com.tech.testng.Config;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.IOException;

public class Demand {
    //Define global variables
    String token ="";
    String styleCode = "";

    //Calling a static member method of a class
    String host = HttpClientUtils.host();

    @BeforeTest
    public void Token() throws IOException {
        //How to get the class object: class name object name = new Class name () Config Object of class
        Config config = new Config();
        config.Login();
        //How to use objects: 1. Access properties: object name.Member variable      2. Access behavior: object name.Method name(...)
        token = config.exchangeToken();//call Config Class, using global variables token The number returned by the receive method Token value
        System.out.println(token);
    }

    @Test(description = "New order")
    public void putOrder() throws IOException {
        String url = host+"/order/web/v1/create";
        //New order
        String params = "{"Id":"68163112","Name":"Short sleeve"}";
        //Directly call the encapsulated request method
        String body = HttpClientUtils.doPut(url,params,token);
        System.out.println("New order successfully created"+body);
    }

    @Test(description = "Order list query",dependsOnMethods = {"putOrder"})
    public String postPage() throws  IOException {
        String url = host+"/web/v1/order/page";
        String params = "{"pageNum":1,"pageSize":20}";
        String body = HttpClientUtils.doPost(url,params,token);

        //jsonpath Extract response fields
        JSONObject jsonObject = JSON.parseObject(body);
        JSONObject data = jsonObject.getJSONObject("data");//obtain data of json object
        JSONArray list = data.getJSONArray("list");//obtain data Medium list Object and use list preservation
        JSONObject jsonObject1 = list.getJSONObject(0);//obtain list Data with subscript 0
        styleCode = jsonObject1.getString("styleCode");//extract styleCode field
        System.out.println(styleCode);
        return styleCode;
    }
}

  4. Production.java under the demand package

Description: use case of business system B

Usage: [deliver after entering data]

package com.tech.demand;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tech.common.HttpClientUtils;
import com.tech.testng.Config;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.io.IOException;

public class Production {
    //Define global variables
    String token ="";
    String styleId ="";
    String demandDetailId ="";
    String orderId ="";
    //Calling a static member method of a class
    String host = HttpClientUtils.host();

    @BeforeTest
    public void Token() throws IOException {
        //How to get the class object: class name object name = new Class name () Config Object of class
        Config config = new Config();
        config.Login();
        //How to use objects: 1. Access properties: object name.Member variable      2. Access behavior: object name.Method name(...)
        token = config.exchangeToken();//call Config Class, using global variables ssotoken The number returned by the receive method Token value
        System.out.println(token);
    }

    @Test(description = "Shipment list query")
    public void getPage() throws IOException {
        String url = host+"/web/v1/info/page?pageNum=1&pageSize=20";
        String body = HttpClientUtils.doGet(url,token);
        System.out.println("Shipment list query succeeded. The response content is:"+body);

        JSONObject jsonObject = JSON.parseObject(body);
        JSONObject data = jsonObject.getJSONObject("data");//obtain data of json object
        JSONArray list = data.getJSONArray("list");//obtain data Medium list Object and use list preservation
        JSONObject jsonObject1 = list.getJSONObject(0);//obtain list Data with subscript 0
        styleId = jsonObject1.getString("styleId");
        demandDetailId = jsonObject1.getString("demandDetailId");
    }

    @Test(description = "deliver goods-Attachment data upload",dependsOnMethods = {"getPage"})
    public void postAdd() throws IOException{
        String url = host+"/web/v1/info/add";
        //Quotation [attachment type (3)-quotation,4-Commodity list]
        String params3 = "{"attachmentType":"3","attachmentUrl":"702074.jpeg"}";
        //Commodity list
        String params4 =  "{"attachmentType":"4","attachmentUrl":"902034.jpeg"}";
        String body = HttpClientUtils.doPost(url,params3,token);
        String body1 = HttpClientUtils.doPost(url,params4,token);
        System.out.println("Quotation uploaded successfully"+body);
        System.out.println("Product list uploaded successfully"+body1);
    }

    @Test(description = "Get shipment details",dependsOnMethods = {"postAdd"})
    public void getDetail() throws IOException{
        String url = host+"/web/v1/production-order/detail/detail-id?demandDetailId="+demandDetailId;
        String body = HttpClientUtils.doGet(url,token);

        JSONObject jsonObject = JSON.parseObject(body);
        JSONObject data = jsonObject.getJSONObject("data");//obtain data of json object
        orderId = data.getString("orderId");//extract orderId
    }
    @Test(description = "Delivery data submission",dependsOnMethods = {"getDetail"},enabled = true)
    public void postSubmit() throws IOException{
        String url = host+"/web/v1/order/submit/"+styleId;
        String params = "{}";
        String body = HttpClientUtils.doPost(url,params,token);
        System.out.println("The shipment is successful, and the response is:"+body);
    }
}

5. Execute TestNG

1) Mode 1: program code execution

Create a new test.java under the testng package. The code is as follows:

package com.tech.testng;

import com.tech.demand.*;import org.testng.TestNG;

import java.io.IOException;

public class test {

    public static void main(String[] args) throws IOException {

        //stay main function call
        TestNG testNG = new TestNG();
        Class[] classes = {Demand.class, Production.class};
        testNG.setTestClasses(classes);
        testNG.run();
    }
}

2) Method 2: execute in XML mode

Create testng.xml in hellotest SRC directory. The code is as follows:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >

<suite name="Suite1" verbose="1" >
    <test name="test1" >
        <classes>
            <class name="com.tech.demand.Demand"></class>
            <class name="com.tech.demand.Production"></class>
        </classes>
    </test>

</suite>

6. Execution results

Ignore, there is no mapping here

4, Summary

The above is the code of the whole project. Of course, only a part of the use cases of the business system are posted, but it does not affect the demonstration project examples.

At the beginning of using testng, list the problems existing in the project and see if there are ways to optimize it later:

  • Status 1: for the. java use case file of the business system, the instance must be logged in before each execution
  • ——>Existing problem: if there are 20. java use case files, you need to log in 20 times after executing a project
  • Status 2: in order to make each. java use case file of the business system run independently, the current processing method is to query the latest data from the list for processing
  • ——>Existing problems: if someone happens to create a piece of data at the same time, the latest data found in the use case is not created by himself in the previous step, but by others, which may lead to problems in the later use cases
  • Status quo 3: a. java use case file may contain many @ tests. Because it is the main process automation, the input parameters need to use the output parameters of the previous interface, so the dependsOnMethods use case dependency is adopted
  • ——>Existing problems: I don't quite understand whether this method conforms to the principle of "use cases should run independently", because if the dependent use case fails, the use case will fail
  • Status quo 4: at present, individuals use programming code to execute use cases
  • ——>Existing problems: after reading the official documents of testng and checking a lot of online materials, it is written that it is executed in xml. Does personal use not conform to the original intention of testng framework design

 

Posted on Sat, 27 Nov 2021 23:20:33 -0500 by Protato