(譯)如何測(cè)試 HTTPS 服務(wù)

原文:How to test Go HTTPS Services

譯文為第一人稱視角:
在DNSimple的微服務(wù)中,在Go的文檔中很難找到描述有關(guān)如何測(cè)試HTTP(S)端服務(wù)的文檔。大部分的文章,我發(fā)現(xiàn)要么是不完整,要么就是缺少一些測(cè)試樣例,特別是有關(guān)集成測(cè)試。

以下是我寫的一些服務(wù)樣例。我希望這個(gè)分享,在你的下一個(gè)Go項(xiàng)目中會(huì)節(jié)省一些測(cè)試的時(shí)間。如果你需要一些靈感來擴(kuò)這個(gè)測(cè)試,請(qǐng)查閱我們的Go客戶端接口,它會(huì)影響域、域名服務(wù)器和證書接口的交互。

開始編寫測(cè)試代碼:

# microservice.go
package microservice

import (
    "fmt"
    "net/http"
)

func NewServer(port string) *http.Server {
    addr := fmt.Sprintf(":%s", port)

    mux := http.NewServeMux()
    mux.HandleFunc("/", handler)

    return &http.Server{
        Addr:    addr,
        Handler: mux,
    }
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}

這是一個(gè)簡(jiǎn)單版本的項(xiàng)目。我們將會(huì)設(shè)置一些暴露出去的函數(shù)來舉例這個(gè)服務(wù)并使用net/http包 和寫一些私有函數(shù),來處理這些接口的方法。
現(xiàn)在讓我們來看寫這個(gè)單元測(cè)。他關(guān)鍵的代碼部分是使用了httptest包:

# microservice_test.go
package microservice

import (
    "bytes"
    "crypto/tls"
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"
    "time"
)

var (
    port = "8080"
)

//
// Unit Tests
//

func TestHandler(t *testing.T) {
    expected := []byte("Hello World")

    req, err := http.NewRequest("GET", buildUrl("/"), nil)
    if err != nil {
        t.Fatal(err)
    }

    res := httptest.NewRecorder()

    handler(res, req)

    if res.Code != http.StatusOK {
        t.Errorf("Response code was %v; want 200", res.Code)
    }

    if bytes.Compare(expected, res.Body.Bytes()) != 0 {
        t.Errorf("Response body was '%v'; want '%v'", expected, res.Body)
    }
}

func buildUrl(path string) string {
    return urlFor("http", port, path)
}

func urlFor(scheme string, serverPort string, path string) string {
    return scheme + "://localhost:" + serverPort + path
}

前面幾行設(shè)置了預(yù)設(shè)的主體和一個(gè)Get請(qǐng)求。它是Go的標(biāo)準(zhǔn)HTTP測(cè)試庫(kù)的一部分,實(shí)例化了一個(gè)新的*httptest.ResponseRecorder方法:

ResponseRecorder方法實(shí)現(xiàn)了http.ResponseWriter,這個(gè)記錄是為接下來的變化而進(jìn)行的測(cè)試。
有了這個(gè)對(duì)象,我們就可以直接調(diào)用程序處理,然后我們可以維護(hù)它,以至于這些返回的HTTP代碼和主體都是如預(yù)期中的一樣。

集成測(cè)試:
單元測(cè)試是非常好的,但是如果我們想包含SSL/TLS握手來測(cè)試微服務(wù)實(shí)際的HTTP(S)請(qǐng)求呢?
在開始之前,我們需要一個(gè)子簽名的測(cè)試證書:

go run $GOROOT/src/crypto/tls/generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,localhost --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h

這個(gè)命令將會(huì)創(chuàng)建兩個(gè)文件:

? ls *.pem
cert.pem key.pem

現(xiàn)在開始寫我們的集成測(cè)試:

func TestHTTPSServer(t *testing.T) {
    srv := NewServer(httpsPort)
    go srv.ListenAndServeTLS("cert.pem", "key.pem")
    defer srv.Close()
    time.Sleep(100 * time.Millisecond)

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }

    client := &http.Client{Transport: tr}
    res, err := client.Get(buildSecureUrl("/"))

    if err != nil {
        t.Fatal(err)
    }

    defer res.Body.Close()

    if res.StatusCode != http.StatusOK {
        t.Errorf("Response code was %v; want 200", res.StatusCode)
    }

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        t.Fatal(err)
    }

    expected := []byte("Hello World")

    if bytes.Compare(expected, body) != 0 {
        t.Errorf("Response body was '%v'; want '%v'", expected, body)
    }
}

首先我們構(gòu)建服務(wù)器(srv),然后我們啟動(dòng)它,分離在一個(gè)線程中,否則這個(gè)進(jìn)程將會(huì)掛起在這一行。我們對(duì)這個(gè)進(jìn)程進(jìn)行了一些睡眠,好讓這個(gè)服務(wù)能夠啟動(dòng)。
現(xiàn)在,我們可以構(gòu)造這個(gè)客戶端是InsecureSkipVerify: true,就好像我們說的一樣客戶端不需要驗(yàn)證簽名就可以進(jìn)行SSl握手。請(qǐng)記住,我們的簽名不是由一個(gè)已知的CA機(jī)構(gòu)頒發(fā)的,而是來自于我們自己的計(jì)算機(jī)。
最后一個(gè)測(cè)試部分,我么可以正真的執(zhí)行一個(gè)HTTP請(qǐng)求來客戶端,和我們要維護(hù)的代碼以及響應(yīng)主體。

總結(jié):

善于閱讀Go的官方文檔,Go的標(biāo)準(zhǔn)庫(kù)擁有所有的測(cè)試工具。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,058評(píng)論 25 709
  • 文章來自:http://blog.csdn.net/mj813/article/details/52451355 ...
    好大一只鵬閱讀 9,363評(píng)論 2 126
  • 七律·巴渝風(fēng)云 巴渝自古多驍漢, 暴葬元朝“上帝鞭”。 萬彈狂轟圍壯士, 千聲怒吼御倭蠻。 碧園談判唇槍熱, 洞...
    任爾風(fēng)云我自逍閱讀 628評(píng)論 0 1
  • 把有序數(shù)組打碎成無序數(shù)組,相同的就自然組合了 https://segmentfault.com/q/1010000...
    angelababa閱讀 2,914評(píng)論 0 0

友情鏈接更多精彩內(nèi)容