繁体   English   中英

golang 单元测试中的 Mocking 特定错误类型

[英]Mocking specific error types in golang unit tests

我一直致力于处理一些 golang 函数中的软故障,并希望为各种故障场景创建一些单元测试。 例如,一些检查包括:

        switch err := err.(type) {
        case net.Error:
                if err.(net.Error).Temporary() || err.(net.Error).Timeout() {
                        ...
                }
        case *url.Error:
                if err, ok := err.Err.(net.Error); ok && err.Timeout() {
                        ...
                }
        case *net.OpError:
                if syscallErr, ok := err.Err.(*os.SyscallError); ok {
                        if syscallErr.Err == syscall.ECONNRESET {
                                ...
                        }
                }
        ...

我相信我只需要我的模拟 function 来返回与这些条件兼容的错误。 我看到 net.Error、net.OpError、url.Error 和 os.SyscallError 类型已导出。 但是,我找不到任何人构造 net.Error 值并返回它的示例 - 人们投入了大量工作来创建以各种方式失败的外部进程,但没有返回 net.Error 超时 function 的示例返回真。

同样,我找不到任何包装不是由 fmt.Errorf 产生的错误的示例,所以我不确定在不使用基本内置错误类型时是否涉及更多的错误。Wrap()。

https://golang.org/pkg/net/#Error是一个interface ,定义TimeoutTemporary将是微不足道的,因为它们只是返回bool

package main

import(
        "fmt"
        "net"
)

type mockNetError struct {
        temporary bool
        timeout bool
}

func (e *mockNetError)Error() string {
        return fmt.Sprintf("mockNetworkError: timeout %b, temporary %b", e.timeout, e.temporary)
}

func (e *mockNetError)Temporary() bool{
        return e.temporary
}

func (e *mockNetError)Timeout() bool{
        return e.timeout
}
func main() {
        var err error = new(mockNetError)
        if nerr, ok := err.(net.Error); ok {
                fmt.Println("It was a network error! %s", nerr.Error())
        }
}

但是,因为net.Error是一个接口类型,所以err.(type)永远不会返回它。 在我的代码中,我断言它可能满足该接口,这与询问它是否是err接口中的值的类型不同。

您从net提到的其他错误不是接口(尽管它们确实满足net.Error )。

https://blog.golang.org/go1.13-errors讨论了错误包装在 go 中的工作原理。

约定而不是更改:包含另一个错误的错误可能会实现返回底层错误的 Unwrap 方法。

%w几乎总是这样做的原因是因为人们几乎总是在错误中添加额外的文本

事实上, net.OsError是一个可以通过提供Unwrap()方法包装另一个错误的示例。

如果您想创建这样的错误,只需:

fmt.Println(net.OpError{
   Op: "mock", 
   Net: "mock",
   Source: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 1234 },                
   Addr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12340 },
   Err: fmt.Errorf("Mock net.OpError"),
})

基于 Daniel Farrell 的回答,我发现了一个 mocking 和 os.SyscallError 的示例,它深埋在 Golang 的 AWS SDK 中。 把它们放在一起,我们得到这个:

return nil, &net.OpError{
                Op:     "mock",
                Net:    "mock",
                Source: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 1234},
                Addr:   &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12340},
                Err:    &os.SyscallError{Syscall: "read", Err: syscall.ECONNRESET},
               }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM