首页 > 其他分享 >Go语言精进之路读书笔记第44条——正确运用fake、stub和mock等辅助单元测试

Go语言精进之路读书笔记第44条——正确运用fake、stub和mock等辅助单元测试

时间:2024-03-10 20:26:05浏览次数:22  
标签:city err string nil 读书笔记 44 单元测试 Weather 替身

44.1 fake:真实组件或服务的简化实现版替身

  • fake测试就是指采用真实组件或服务的简化版实现作为替身,以满足被测代码的外部依赖需求。
  • 使用fake替身进行测试的最常见理由是在测试环境无法构造被测代码所依赖的外部组件或服务,或者这些组件/服务有副作用。
type fakeOkMailer struct{}

func (m *fakeOkMailer) SendMail(subject string, dest string, body string) error {
    return nil
}

func TestComposeAndSendOk(t *testing.T) {
    m := &fakeOkMailer{}
    mc := mailclient.New(m)
    _, err := mc.ComposeAndSend("hello, fake test", []string{"[email protected]"}, "the test body")
    if err != nil {
        t.Errorf("want nil, got %v", err)
    }
}

type fakeFailMailer struct{}

func (m *fakeFailMailer) SendMail(subject string, dest string, body string) error {
    return fmt.Errorf("can not reach the mail server of dest [%s]", dest)
}

func TestComposeAndSendFail(t *testing.T) {
    m := &fakeFailMailer{}
    mc := mailclient.New(m)
    _, err := mc.ComposeAndSend("hello, fake test", []string{"[email protected]"}, "the test body")
    if err == nil {
        t.Errorf("want non-nil, got nil")
    }
}

44.2 stub:对返回结果有一定预设控制能力的替身

stub替身增强了对替身返回结果的间接控制能力,这种控制可以通过测试前对调用结果预设置来实现。

被测代码

type Weather struct {
    City    string `json:"city"`
    Date    string `json:"date"`
    TemP    string `json:"temP"`
    Weather string `json:"weather"`
}

func GetWeatherInfo(addr string, city string) (*Weather, error) {
    url := fmt.Sprintf("%s/weather?city=%s", addr, city)
    resp, err := http.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return nil, fmt.Errorf("http status code is %d", resp.StatusCode)
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var w Weather
    err = json.Unmarshal(body, &w)
    if err != nil {
        return nil, err
    }

    return &w, nil
}

测试代码:我们使用httptest建立了一个天气服务器替身

var weatherResp = []Weather{
    {
        City:    "nanning",
        TemP:    "26~33",
        Weather: "rain",
        Date:    "05-04",
    },
    {
        City:    "guiyang",
        TemP:    "25~29",
        Weather: "sunny",
        Date:    "05-04",
    },
    {
        City:    "tianjin",
        TemP:    "20~31",
        Weather: "windy",
        Date:    "05-04",
    },
}

func TestGetWeatherInfoOK(t *testing.T) {
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        var data []byte

        if r.URL.EscapedPath() != "/weather" {
            w.WriteHeader(http.StatusForbidden)
        }

        r.ParseForm()
        city := r.Form.Get("city")
        if city == "guiyang" {
            data, _ = json.Marshal(&weatherResp[1])
        }
        if city == "tianjin" {
            data, _ = json.Marshal(&weatherResp[2])
        }
        if city == "nanning" {
            data, _ = json.Marshal(&weatherResp[0])
        }

        w.Write(data)
    }))
    defer ts.Close()
    addr := ts.URL

    city := "guiyang"
    w, err := GetWeatherInfo(addr, city)
    if err != nil {
        t.Fatalf("want nil, got %v", err)
    }
    if w.City != city {
        t.Errorf("want %s, got %s", city, w.City)
    }
    if w.Weather != "sunny" {
        t.Errorf("want %s, got %s", "sunny", w.City)
    }
}

44.3 mock:专用于行为观察和验证的替身

  • 能力:mock能提供测试前的预设置返回结果能力,还可以对mock替身对象在测试过程中的行为进行观察和验证
  • 局限性:mock只用于实现某接口的实现类型的替身;一般需要第三方框架支持(github.com/golang/mock/gomock)

标签:city,err,string,nil,读书笔记,44,单元测试,Weather,替身
From: https://www.cnblogs.com/brynchen/p/18064717

相关文章

  • Go语言精进之路读书笔记第45条——使用模糊测试让潜在bug无处遁形
    模糊测试就是指半自动地为程序提供非法的、非预期、随机的数据,并监控程序在这些输入数据下是否会出现崩溃、内置断言失败、内存泄漏、安全漏洞等情况。45.1模糊测试在挖掘Go代码的潜在bug中的作用DmitryVyukov2015年使用go-fuzz在Go标准库中发现了137个bug。45.2go-fuzz的......
  • Go语言精进之路读书笔记第46条——为被测对象建立性能基准
    46.1性能基准测试在Go语言中是“一等公民”性能基准测试在Go语言中和普通的单元测试一样被原生支持的,得到的是“一等公民”的待遇。我们可以像对普通单元测试那样在*_test.go文件中创建被测对象的性能基准测试,每个以Benchmark前缀开头的函数都会被当作一个独立的性能基准测试。......
  • Go语言精进之路读书笔记第48条——使用expvar输出度量数据,辅助定位性能瓶颈点
    48.1expvar包的工作原理Go标准库中的expvar包提供了一种输出应用内部状态信息的标准化方案,这个方案标准化了以下三方面内容:数据输出接口形式输出数据的编码格式用户自定义性能指标的方法import(_"expvar""fmt""net/http")funcmain(){http.Hand......
  • Go语言精进之路读书笔记第47条——使用pprof对程序进行性能剖析
    47.1pprof的工作原理1.采样数据类型(1)CPU数据(2)堆内存分配数据(3)锁竞争数据(4)阻塞时间数据2.性能数据采集的方式(1)通过性能基准测试进行数据采集gotest-bench.xxx_test.go-cpuprofile=cpu.profgotest-bench.xxx_test.go-memprofile=mem.profgotes......
  • Go语言精进之路读书笔记第49条——使用Delve调试Go代码
    49.1关于调试,你首先应该知道的几件事1.调试前,首先做好心理准备2.预防bug的发生,降低bug的发生概率(1)充分的代码检查(2)为调试版添加断言(3)充分的单元测试(4)代码同级评审3.bug的原因定位和修正(1)收集“现场数据”(2)定位问题所在(3)修正并验证49.2Go调试工......
  • ABC344G 笔记
    题意给定\(N\)个二维平面上的点\((X_i,Y_i)\)与\(Q\)组询问,每组询问给出一条直线\(Y=A_iX+B_i\),问有多少个点在直线上方(或者在直线上)。也就是询问有多少个\((X_i,Y_i)\),满足\(Y_i\geA_j\timesX_i+B_j\)。题解首先这个式子是\(A\timesX+B\leY\),移项......
  • AtCoder Beginner Contest 344
    A-Spoiler#include<bits/stdc++.h>usingnamespacestd;usingi32=int32_t;usingi64=int64_t;usingldb=longdouble;#defineinti64usingvi=vector<int>;usingpii=pair<int,int>;constintmod=998244353;constintinf......
  • abc344E 维护元素唯一的序列
    给定序列A[N],元素值各不相同,有Q个操作,格式如下:1xy:在元素x后面插入元素y,保证插入时x唯一。2x:将元素x从序列中删除,保证删除时x唯一。输出所有操作完成后的序列。1<=N,Q<=2E5;1<=A[i]<=1E9;A[i]!=A[j]用链表来快速插入和删除,另外还需要map来快速定位,类似LRU的实现。......
  • ABC344G 题解
    ABC344G题解给定平面上\(n\)个点和\(q\)条直线,问对于每条线,有多少点在它上方。形式化的,对于直线\(y=ax+b\)统计有多少点\((x,y)\)满足\(y\geax+b\),即\(-ax+y\geb\)。故我们可以将所有点按照\(-ax+y\)排序,从而利用二分简单的得出结果。但是我们显然不可能暴力进......
  • AtCoder Beginner Contest 344
    AtCoderBeginnerContest344ABCD略EInsertorErase手写链表调了这么久。。链表模板。FEarntoAdvance考虑DP,但是我们发现不是很好转移,然后我们发现\(n\le80\),我们观察一下题目的性质。如果路径确定了,那么我们肯定会在最大值的地方使劲加到终点为止。那么我们考......