如何模拟DNS请求? (miekg / DNS)

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?

Here is the full code in case anyone's curious.

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.