1

我试图在 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")
    }
}

最小可复制示例:

4

3 回答 3

5

您可以使用方法表达式将方法绑定到函数类型的变量,就像您已经将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

于 2021-08-26T15:43:21.007 回答
1

国际海事组织。你可以注入函数和net.Interface函数getAddrs进入[]net.AddrsGetIpAddress

type NetworkHandler struct {
    GetInterfaces func() ([]net.Interface,error)
    GetAddrsFromInterface func(p net.Interface) ([]net.Addr,error)
}
func GetIpAddress(networkHandler NetworkHandler) (net.IP,error) {
    // On récupère la liste des interfaces
    ifaces, err := networkHandler.GetInterfaces()
    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)
            _, err := networkHandler.GetAddrsFromInterface(i)

            // ex
            if err != nil {
                return nil, err
            }
            // Some treatments on addrs...
        }
    }

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

ON 测试代码

func TestGetIpAddress(t *testing.T) {
    t.Run("should return error when cannot get address from net.interface", func(t *testing.T) {
        result, err := GetIpAddress(NetworkHandler{
            GetInterfaces:         mockGetInterfaces,
            GetAddrsFromInterface: mockGetAddrs,
        })

        assert.Nil(t, result)
        assert.Error(t, err)
        assert.Equal(t, "cannot get addrs",err.Error())
    })
}
func mockGetInterfaces() ([]net.Interface,error) {
    return []net.Interface{
        {Name:         "wlan0"},
        {Name:         "eth0"}},nil
}

// stub behavior when calling net.Interface{}.Addrs()
func mockGetAddrs(i net.Interface) ([]net.Addr,error) {
    return nil, errors.New("cannot get addrs")
}

关于使用

func main() {
    GetIpAddress(NetworkHandler{
        GetInterfaces:         net.Interfaces,
        GetAddrsFromInterface: func(p net.Interface) ([]net.Addr, error) {
            return p.Addrs()
        },
    })
}

于 2021-08-27T07:16:05.537 回答
-1

如果可以的话,将该函数包装成一个类型,然后用它来安排 jit.

package main

import (
    "errors"
    "fmt"
    "net"
)

func main() {
    fmt.Println("Hello, playground")
    var myfn listInterfaces = func() ([]net.Interface, error) {
        return nil, fmt.Errorf("it will never happen")
    }
    addrs, err := myfn.GetIPAddress()
    fmt.Println(addrs, err)
}

type listInterfaces func() ([]net.Interface, error)

func (j listInterfaces) GetIPAddress() (net.IP, error) {
    // On récupère la liste des interfaces
    ifaces, err := j()
    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")
}

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

于 2021-08-26T14:39:43.843 回答