如何模拟 net.Interface

Win*_*ito 1 interface mocking go gomock

我正在尝试在 Go 中模拟 net.Interface,我使用 net.Interfaces() 并且我想要一个固定的回报。但 net.Interface 不是一个接口,所以我不能用 gomock 来模拟它。

\n

也许我的测试方式是错误的。

\n

这是我要测试的方法:

\n
const InterfaceWlan = "wlan0"\nconst InterfaceEthernet = "eth0"\n\nvar netInterfaces = net.Interfaces\n\nfunc GetIpAddress() (net.IP, error) {\n    // On r\xc3\xa9cup\xc3\xa8re la liste des interfaces\n    ifaces, err := netInterfaces()\n    if err != nil {\n        return nil, err\n    }\n\n    // On parcours la liste des interfaces\n    for _, i := range ifaces {\n        // Seul l\'interface Wlan0 ou Eth0 nous int\xc3\xa9resse\n        if i.Name == InterfaceWlan || i.Name == InterfaceEthernet {\n            // On r\xc3\xa9cup\xc3\xa8re les adresses IP associ\xc3\xa9 (g\xc3\xa9n\xc3\xa9ralement IPv4 et IPv6)\n            addrs, err := i.Addrs()\n\n            // Some treatments on addrs...\n        }\n    }\n\n    return nil, errors.New("network: ip not found")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是我暂时写的测试

\n
func TestGetIpAddress(t *testing.T) {\n    netInterfaces = func() ([]net.Interface, error) {\n        // I can create net.Interface{}, but I can\'t redefine \n        // method `Addrs` on net.Interface\n    }\n    \n    address, err := GetIpAddress()\n    if err != nil {\n        t.Errorf("GetIpAddress: error = %v", err)\n    }\n\n    if address == nil {\n        t.Errorf("GetIpAddress: errror = address ip is nil")\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

最小可重现示例:

\n\n

bcm*_*lls 5

您可以使用方法表达式net.Interfaces将方法绑定到函数类型的变量,这与将函数绑定到变量的方式大致相同:

\n
var (\n    netInterfaces     = net.Interfaces\n    netInterfaceAddrs = (*net.Interface).Addrs\n)\n\nfunc GetIpAddress() (net.IP, error) {\n    \xe2\x80\xa6\n            // Get IPs (mock method Addrs ?)\n            addrs, err := netInterfaceAddrs(&i)\n    \xe2\x80\xa6\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后,在测试中,您可以用相同的方式更新绑定:

\n
func TestGetIpAddress(t *testing.T) {\n    \xe2\x80\xa6\n    netInterfaceAddrs = func(i *net.Interface) ([]net.Addr, error) {\n        return []net.Addr{}, nil\n    }\n    \xe2\x80\xa6\n}\n
Run Code Online (Sandbox Code Playgroud)\n

https://play.golang.org/p/rqb0MDclTe2

\n
\n

也就是说,我建议将模拟方法分解为结构类型,而不是覆盖全局变量。这允许测试并行运行,并且还允许包的下游用户编写自己的测试,而无需改变全局状态。

\n
// A NetEnumerator enumerates local IP addresses.\ntype NetEnumerator struct {\n    Interfaces     func() ([]net.Interface, error)\n    InterfaceAddrs func(*net.Interface) ([]net.Addr, error)\n}\n\n// DefaultEnumerator returns a NetEnumerator that uses the default\n// implementations from the net package.\nfunc DefaultEnumerator() NetEnumerator {\n    return NetEnumerator{\n        Interfaces:     net.Interfaces,\n        InterfaceAddrs: (*net.Interface).Addrs,\n    }\n}\n\nfunc GetIpAddress(e NetEnumerator) (net.IP, error) {\n    \xe2\x80\xa6\n}\n
Run Code Online (Sandbox Code Playgroud)\n

https://play.golang.org/p/PLIXuOpH3ra

\n