如何模拟 net.Interface
How to mock net.Interface
我试图在 Go 中模拟 net.Interface,我使用 net.Interfaces() 并且我想要一个固定的 return。但是 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")
}
}
最小可复制示例:
如果可以的话,把那个函数包装成一个类型,然后用它来安排 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")
}
您可以使用 method expression 将方法绑定到函数类型的变量,这与您已经将 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) {
…
}
海事组织。您可以将函数 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()
},
})
}
我试图在 Go 中模拟 net.Interface,我使用 net.Interfaces() 并且我想要一个固定的 return。但是 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")
}
}
最小可复制示例:
如果可以的话,把那个函数包装成一个类型,然后用它来安排 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")
}
您可以使用 method expression 将方法绑定到函数类型的变量,这与您已经将 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) {
…
}
海事组织。您可以将函数 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()
},
})
}