I have this small piece of code to explain the codebase I'm trying to test. I've skipped checking errors to make the question short.
func lastCNAME(domain string) (lastCNAME string) {
ns := "8.8.8.8:53"
c := dns.Client{}
m := dns.Msg{}
m.SetQuestion(domain, dns.TypeA)
r, _, _ := c.Exchange(&m, ns)
// Last CNAME
for _, ans := range r.Answer {
cname, ok := ans.(*dns.CNAME)
if ok {
lastCNAME = cname.Target
}
}
return lastCNAME
}
What is the best way to mock the dns query to the nameserver 8.8.8.8
?
You could create an interface for the func in question and provide a stubbed implementation in testing:
package main
import (
"fmt"
"github.com/miekg/dns"
)
type LastCnamer interface {
LastCname(domain string) (lastCname string, err error)
}
type LastCnameResolver string
func (l LastCnameResolver) LastCname(domain string) (lastCname string, err error) {
ns := string(l)
c := dns.Client{}
m := dns.Msg{}
m.SetQuestion(domain, dns.TypeA)
r, _, err := c.Exchange(&m, ns)
if err != nil {
return lastCname, err
}
// Last CNAME
for _, ans := range r.Answer {
cname, ok := ans.(*dns.CNAME)
if ok {
lastCname = cname.Target
}
}
return lastCname, nil
}
type LastCnameStub map[string]string
func (m LastCnameStub) LastCname(domain string) (string, error) {
return m[domain], nil
}
func main() {
m := make(map[string]string)
m["www.linkedin.com."] = "pop-tmu1-alpha.www.linkedin.com."
var l LastCnamer = LastCnameStub(m)
cname, _ := l.LastCname("www.linkedin.com.")
fmt.Println("Stub", cname)
l = LastCnameResolver("8.8.8.8:53")
cname, err := l.LastCname("www.linkedin.com.")
if err != nil {
panic(err)
}
fmt.Println("Resolved", cname)
}
Or you make the DNS IP in question configurable so it can be exchanged in testing and start a local DNS server (there's a server in the github.com/miekg/dns
package), but that would be some more code including selecting a random free port and using that in the tests.