如何模拟net.Interface



我在试着模仿网络。接口在Go中,我使用net.Interfaces(),我想有一个固定的返回。但净。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")
}
}

最小可复制示例:

  • network.go
  • network_test.go

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

IMO。可以注入函数net.Interface和函数getAddrs使[]net.Addrs进入GetIpAddress

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()
},
})
}

相关内容

  • 没有找到相关文章

最新更新