2016-11-18 77 views
0

我目前正在研究为Go中的服务创建一些单元测试,以及在该功能之上构建的其他函数,我想知道什么是单元测试的最佳方式那在Go?我的代码如下所示:golang中的单元测试

type BBPeripheral struct { 
    client *http.Client 
    endpoint string 
} 

type BBQuery struct { 
    Name string `json:"name"` 
} 

type BBResponse struct { 
    Brand   string `json:"brand"` 
    Model   string `json:"model"` 
    ... 
} 

type Peripheral struct { 
    Brand   string 
    Model   string 
    ... 
} 

type Service interface { 
    Get(name string) (*Peripheral, error) 
} 

func NewBBPeripheral(config *peripheralConfig) (*BBPeripheral, error) { 
    transport, err := setTransport(config) 
    if err != nil { 
     return nil, err 
    } 

    BB := &BBPeripheral{ 
     client: &http.Client{Transport: transport}, 
     endpoint: config.Endpoint[0], 
    } 

    return BB, nil 
} 


func (this *BBPeripheral) Get(name string) (*Peripheral, error) { 

    data, err := json.Marshal(BBQuery{Name: name}) 
    if err != nil { 
     return nil, fmt.Errorf("BBPeripheral.Get Marshal: %s", err) 
    } 

    resp, err := this.client.Post(this.endpoint, "application/json", bytes.NewBuffer(data)) 
    if resp != nil { 
     defer resp.Body.Close() 
    } 
    if err != nil { 
     return nil, err 
    } 
    if resp.StatusCode != http.StatusOK { 
     return nil, fmt.Errorf(resp.StatusCode) 
    } 

    var BBResponse BBResponse 

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

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

    peripheral := &Peripheral{} 

    peripheral.Model = BBResponse.Model 
    if peripheral.Model == "" { 
     peripheral.Model = NA 
    } 

    peripheral.Brand = BBResponse.Brand 
    if peripheral.Brand == "" { 
     peripheral.Brand = NA 
    } 

    return peripheral, nil 
} 

测试该代码,并使用这些功能来旋转了一个单独的goroutine要像服务器上,使用http.httptest包,还是其他什么东西的代码的最有效的方法是什么?这是我第一次尝试编写测试,然后我不知道如何。

+2

Go有自己内置的测试工具。看到这里https://golang.org/pkg/testing/ ...如果你在github上玩游戏以查看其他使用得当的软件包,你会经常遇到以_test.go结尾的文件..这些文件是进行单元测试,但使用cmd go测试并使用测试包。你提到的软件包也是一个很好的开始。在测试之后,因为这是一个服务器,我可能会跟进一个Siege测试来给服务器增加一些压力,看看它是如何处理的https://www.joedog.org/siege-home/ – reticentroot

回答

1

它确实完全取决于。 Go提供了几乎所有的测试应用程序所需的工具。

单元测试,因为不会有太多的技巧,以动态地提供模拟/存根对象

设计是非常重要的。您可以覆盖测试的变量,但它可以解决清理时出现的各种问题。我会专注于IO免费单元测试,以检查您的特定逻辑是否有效。

例如,您可以测试BBPeripheral.Get方法,使client为接口,在实例化时需要它,并为测试提供一个存根。

func Test_BBPeripheral_Get_Success(*testing.T) { 
    bb := BBPeripheral{client: &StubSuccessClient, ...} 
    p, err := bb.Get(...) 
    if err != nil { 
    t.Fail() 
    } 
} 

然后,你可以创建一个练习错误处理的Get方法存根错误客户端:

func Test_BBPeripheral_Get_Success(*testing.T) { 
    bb := BBPeripheral{client: &StubErrClient, ...} 
    _, err := bb.Get(...) 
    if err == nil { 
    t.Fail() 
    } 
} 

组件/集成测试

这些测试可以帮助锻炼是每个单位在你的包裹里可以一起工作。由于您的代码通过http协商,Go提供了可以使用的httptest包。

要做到这一点,测试可以创建一个httptest服务器,并注册一个处理程序来提供this.endpoint所期望的响应。然后,您可以使用其公共界面请求NewBBPeripheral,传入this.endpoint对应的Server.URL属性。

这使您可以模拟您的代码与真实服务器交谈。

去例行检验

转到使得它很容易编写并发代码,并使它一样容易测试。测试生成执行NewBBPeripheral的去例程的顶级代码可能看起来非常像上面的测试。除了启动测试服务器之外,测试还需要等待异步代码完成。如果您没有广泛的服务取消/关闭/信号完整的服务,那么可能需要使用go例程对其进行测试。

竞争危害/负载测试

使用转到内置的bechmark测试与-race标志结合在一起,你可以轻松地锻炼你的代码,并简介它竞争条件,充分利用你上面写的测试。


有一点要记住,如果你的应用的实现仍然在不断变化,编写单元测试可能会花费大量的时间。创建一个测试代码,这些测试代码可以执行代码的公共接口,可以让您轻松验证您的应用程序是否正在运行,同时允许实现发生变化。