The original plan after learning the HTTP client Golang language practice, can continue to, I didn’t think pretty good, at the time of searching information found in addition to Golang SDK comes with.net/HTTP, a more cattle HttpClient realization github.com/valyala/fasthttp, It is said that the performance is 10 times better than NET/HTTP, I think it is a bit exaggerated, I will test it later to make sure.

In github.com/valyala/fasthttp use the object pool, in order to reduce memory use in high performance tests, fasthttp USES two object pool (I only saw the two) : RequestPool sync.Pool responsePool sync.Pool fasthttp also provides a normal object creation API, which I will write about later in the case.

Basic API Demo

First, share the basic usage encapsulation:

PS: This is a practice version, so there are not many comments.

package ft

import (
	"encoding/json"
	"fmt"
	"funtester/task"
	"github.com/valyala/fasthttp"
)


func FastGet(url string, args map[string]interface{}) ([]byte, error) {
	uri := url + "?" + task.ToValues(args)
	_, resp, err := fasthttp.Get(nil, uri)
	iferr ! =nil {
		fmt.Println("Request failed :", err.Error())
		return nil, err
	}
	return resp, err
}

func FastPostForm(url string, args map[string]interface{}) ([]byte, error) {

	// Populate the form, similar to net/ URL
	params := &fasthttp.Args{}
	for s, i2 := range args {
		sprintf := fmt.Sprintf("%v", i2)
		params.Add(s, sprintf)
	}
	_, resp, err := fasthttp.Post(nil, url, params)
	iferr ! =nil {
		fmt.Println("Request failed :", err.Error())
		return nil, err
	}
	return resp, nil
}

func FastPostJson(url string, args map[string]interface{}) ([]byte, error) {

	req := &fasthttp.Request{}
	req.SetRequestURI(url)

	marshal, _ := json.Marshal(args)
	req.SetBody(marshal)

	// Application /x-www-form-urlencoded by default, it doesn't matter
	req.Header.SetContentType("application/json")
	req.Header.SetMethod("POST")

	resp := &fasthttp.Response{}
	iferr := fasthttp.Do(req, resp); err ! =nil {
		fmt.Println("Request failed :", err.Error())
		return nil, err
	}
	return resp.Body(), nil
}

Copy the code

There are two main points to note:

  • FastGet, FastPostForm use fasthttp provide default access request, FastPostJson using custom requests and get a response
  • About the request Header the req. Header. SetContentType method, in fact, it doesn’t matter, can parse the service side

High-performance API Demo

Here’s how to create requests and get responses using apis with higher performance (object pooling) :

package task

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
	"log"
	"time"
)

var FastClient fasthttp.Client = fastClient()

// FastGet gets the GET request object without resource reclamation
// @Description:
// @param url
// @param args
// @return *fasthttp.Request
func FastGet(url string, args map[string]interface{}) *fasthttp.Request {
	req := fasthttp.AcquireRequest()
	req.Header.SetMethod("GET")
	values := ToValues(args)
	req.SetRequestURI(url + "?" + values)
	return req
}

// FastPostJson POST request JSON parameters, no resource reclamation
// @Description:
// @param url
// @param args
// @return *fasthttp.Request
func FastPostJson(url string, args map[string]interface{}) *fasthttp.Request {
	req := fasthttp.AcquireRequest()
	// The default is Application /x-www-form-urlencoded
	req.Header.SetContentType("application/json")
	req.Header.SetMethod("POST")
	req.SetRequestURI(url)
	marshal, _ := json.Marshal(args)
	req.SetBody(marshal)
	return req
}

// FastPostForm POST requests the form to be passed without resource reclamation
// @Description:
// @param url
// @param args
// @return *fasthttp.Request
func FastPostForm(url string, args map[string]interface{}) *fasthttp.Request {
	req := fasthttp.AcquireRequest()
	// The default is Application /x-www-form-urlencoded
	//req.Header.SetContentType("application/json")
	req.Header.SetMethod("POST")
	req.SetRequestURI(url)
	marshal, _ := json.Marshal(args)
	req.BodyWriter().Write([]byte(ToValues(args)))
	req.BodyWriter().Write(marshal)
	return req
}

// FastResponse Retrieves the response to ensure resource reclamation
// @Description:
// @param request
// @return []byte
// @return error
func FastResponse(request *fasthttp.Request) ([]byte, error) {
	response := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(response)
	defer fasthttp.ReleaseRequest(request)
	iferr := FastClient.Do(request, response); err ! =nil {
		log.Println("Response error.")
		return nil, err
	}
	return response.Body(), nil
}

// DoGet sends a GET request to GET the response
// @Description:
// @param url
// @param args
// @return []byte
// @return error
func DoGet(url string, args map[string]interface{}) ([]byte, error) {
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req) // Resources need to be released when they are used up
	req.Header.SetMethod("GET")
	values := ToValues(args)
	req.SetRequestURI(url + "?" + values)
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp) // Resources need to be released when they are used up
	iferr := FastClient.Do(req, resp); err ! =nil {
		fmt.Println("Request failed :", err.Error())
		return nil, err
	}
	return resp.Body(), nil
}

// fastClient Obtains the fast client
// @Description:
// @return fasthttp.Client
func fastClient(a) fasthttp.Client {
	return fasthttp.Client{
		Name:                     "FunTester",
		NoDefaultUserAgentHeader: true,
		TLSConfig:                &tls.Config{InsecureSkipVerify: true},
		MaxConnsPerHost:          2000,
		MaxIdleConnDuration:      5 * time.Second,
		MaxConnDuration:          5 * time.Second,
		ReadTimeout:              5 * time.Second,
		WriteTimeout:             5 * time.Second,
		MaxConnWaitTimeout:       5 * time.Second,
	}
}

Copy the code

Testing services

Using the moco_FunTester framework again, the script is as follows:

package com.mocofun.moco.main

import com.funtester.utils.ArgsUtil
import com.mocofun.moco.MocoServer
import org.apache.tools.ant.taskdefs.condition.And

class Share extends MocoServer {

    static void main(String[] args) {
        def util = new ArgsUtil(args)
        // def server = getServerNoLog(util.getintordefault (0,12345))
        def server = getServer(util.getIntOrdefault(0.12345))
        server.get(both(urlStartsWith("/test"),existArgs("code"))).response("Get request")
        server.post(both(urlStartsWith("/test"), existForm("fun"))).response("Post request form")
        server.post(both(urlStartsWith("/test"), existParams("fun"))).response("Post request JSON form")
        server.get(urlStartsWith("/qps")).response(qps(textRes("Congratulations on reaching QPS!"), 1))
Server. response(delay(jsonRes(getJson("Have=Fun ~ Tester!" )), 1000))
        server.response("Have Fun ~ Tester!")
        def run = run(server)
        waitForKey("fan")
        run.stop()
    }
}

Copy the code

Golang unit tests

It was the first time to write Golang single test, but I didn’t get used to it for a long time.

package test

import (
	"funtester/ft"
	"funtester/task"
	"log"
	"testing"
)

const url = "http://localhost:12345/test"

func args(a) map[string]interface{} {
	return map[string]interface{} {"code": 32."fun":  32."msg":  "324",}}func TestGet(t *testing.T) {
	get := task.FastGet(url, args())
	res, err := task.FastResponse(get)
	iferr ! =nil {
		t.Fail()
	}
	v := string(res)
	log.Println(v)
	ifv ! ="Get request" {
		t.Fail()
	}
}

func TestPostJson(t *testing.T) {
	post := task.FastPostJson(url, args())
	res, err := task.FastResponse(post)
	iferr ! =nil {
		t.Fail()
	}
	v := string(res)
	log.Println(v)
	ifv ! ="Post request JSON form" {
		t.Fail()
	}
}

func TestPostForm(t *testing.T) {
	post := task.FastPostForm(url, args())
	res, err := task.FastResponse(post)
	iferr ! =nil {
		t.Fail()
	}
	v := string(res)
	log.Println(v)
	ifv ! ="Post request form" {
		t.Fail()
	}
}

func TestGetNor(t *testing.T) {
	res, err := ft.FastGet(url, args())
	iferr ! =nil {
		t.Fail()
	}
	v := string(res)
	log.Println(v)
	ifv ! ="Get request" {
		t.Fail()
	}
}

func TestPostJsonNor(t *testing.T) {
	res, err := ft.FastPostJson(url, args())
	iferr ! =nil {
		t.Fail()
	}
	v := string(res)
	log.Println(v)
	ifv ! ="Post request JSON form" {
		t.Fail()
	}
}

func TestPostFormNor(t *testing.T) {
	res, err := ft.FastPostForm(url, args())
	iferr ! =nil {
		t.Fail()
	}
	v := string(res)
	log.Println(v)
	ifv ! ="Post request form" {
		t.Fail()
	}
}

Copy the code

The test report

Output from the console:

=== RUN TestGet 2021/10/18 18:56:49 get request -- PASS: TestGet (0.01s) === RUN TestPostJson 2021/10/18 18:56:49 POST request JSON form -- PASS: TestPostJson (0.00s) === RUN TestPostForm 2021/10/18 18:56:49 Post request form -- PASS: TestPostForm (0.00s) === RUN TestGetNor 2021/10/18 18:56:49 Get request -- PASS: TestGetNor (0.00s) === RUN TestPostJsonNor 2021/10/18 18:56:49 POST request JSON form -- PASS: TestPostJsonNor (0.00s) === RUN TestPostFormNor 2021/10/18 18:56:49 Post request form -- PASS: TestPostFormNor (0.00s) === RUN TestStageJSONCopy the code

Have Fun ~ Tester!

  • FunTester test framework architecture diagram
  • JMeter Chinese Operation Manual with a sense of time
  • 140 interview questions (UI, Linux, MySQL, API, security)
  • Graphic HTTP brain map
  • Share a Fiddler study bag
  • JVM command brain map for testing
  • The Definitive Guide to Java Performance
  • JSON based
  • HTTP asynchronous connection pooling and multithreading practices
  • Bind mobile phone number performance test
  • Discussion on assembly point and multi-stage synchronization in performance testing
  • How to become a Full stack automation engineer
  • LT browser – responsive web testing tool
  • Simplify test cases