首页 > 解决方案 > 如何模拟net.Interface

问题描述

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

也许我测试的方式错了。

这是我要测试的方法:

const InterfaceWlan = "wlan0"
const InterfaceEthernet = "eth0"

var netInterfaces = net.Interfaces

func GetIpAddress() (net.IP, error) {
    // On récupère la liste des interfaces
    ifaces, err := netInterfaces()
    if err != nil {
        return nil, err
    }

    // On parcours la liste des interfaces
    for _, i := range ifaces {
        // Seul l'interface Wlan0 ou Eth0 nous intéresse
        if i.Name == InterfaceWlan || i.Name == InterfaceEthernet {
            // On récupère les adresses IP associé (généralement IPv4 et IPv6)
            addrs, err := i.Addrs()

            // Some treatments on addrs...
        }
    }

    return nil, errors.New("network: ip not found")
}

这是我暂时写的测试

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

    if address == nil {
        t.Errorf("GetIpAddress: errror = address ip is nil")
    }
}

最小可复制示例:

标签: gointerfacemockinggomock

解决方案


您可以使用方法表达式将方法绑定到函数类型的变量,就像您已经将net.Interfaces函数绑定到变量一样:

var (
    netInterfaces     = net.Interfaces
    netInterfaceAddrs = (*net.Interface).Addrs
)

func GetIpAddress() (net.IP, error) {
    …
            // Get IPs (mock method Addrs ?)
            addrs, err := netInterfaceAddrs(&i)
    …
}

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

func TestGetIpAddress(t *testing.T) {
    …
    netInterfaceAddrs = func(i *net.Interface) ([]net.Addr, error) {
        return []net.Addr{}, nil
    }
    …
}

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


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

// A NetEnumerator enumerates local IP addresses.
type NetEnumerator struct {
    Interfaces     func() ([]net.Interface, error)
    InterfaceAddrs func(*net.Interface) ([]net.Addr, error)
}

// DefaultEnumerator returns a NetEnumerator that uses the default
// implementations from the net package.
func DefaultEnumerator() NetEnumerator {
    return NetEnumerator{
        Interfaces:     net.Interfaces,
        InterfaceAddrs: (*net.Interface).Addrs,
    }
}

func GetIpAddress(e NetEnumerator) (net.IP, error) {
    …
}

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


推荐阅读