Mocking DNS
See it in action
MockServer can run a built-in UDP DNS server alongside its HTTP(S) ports, so a test can mock DNS resolution (an A record pointing a hostname at a test double, an MX record, a deliberately missing record, and so on) with the same expectation, matching and verification API used for HTTP. A DNS expectation matches on a DnsRequestDefinition (the queried name, record type and class) and responds with a DnsResponse action (answer/authority/additional records and a response code).
- Enable DNS mocking — the DNS server is off by default. Turn it on and (optionally) pick a port:
ClientAndServer mockServer = ClientAndServer.startClientAndServer(
configuration().dnsEnabled(true).dnsPort(5353)
);
See DNS Configuration for every way to set dnsEnabled / dnsPort (system property, environment variable, property file) and for what happens if MockServer cannot bind the port.
- Create a DNS expectation — match a query by name (and, optionally, record type) and respond with one or more records:
import static org.mockserver.model.DnsRequestDefinition.dnsRequest;
import static org.mockserver.model.DnsResponse.dnsResponse;
import static org.mockserver.model.DnsRecord.aRecord;
import static org.mockserver.model.DnsRecordType.A;
new MockServerClient("localhost", 1080)
.when(
dnsRequest("example.com", A)
)
.respondWithDns(
dnsResponse()
.withAnswerRecord(aRecord("example.com", "127.0.0.1"))
);
var mockServerClient = require('mockserver-client').mockServerClient;
mockServerClient("localhost", 1080).respondWithDns(
{ dnsName: "example.com", dnsType: "A" },
{
answerRecords: [
{ name: "example.com", type: "A", value: "127.0.0.1" }
],
responseCode: "NOERROR"
}
).then(
function () { console.log("expectation created"); },
function (error) { console.log(error); }
);
See REST API for full JSON specification
Unlike the other tabs on this page, this JavaScript example only answers the first matching DNS query. respondWithDns (and every other respondWith... convenience method in the JS client) defaults its own times argument to { remainingTimes: 1, unlimited: false } when omitted — unlike the server's own default (unlimited) that the REST tab, Java, Python, Ruby, Go and .NET examples all get by leaving times out of the request entirely. Pass an explicit times argument (a number, or { unlimited: true }) as the third argument to match more than once: respondWithDns(requestMatcher, dnsResponse, { unlimited: true }).
from mockserver import MockServerClient, DnsRequestDefinition, DnsResponse, DnsRecord
client = MockServerClient("localhost", 1080)
client.when(
DnsRequestDefinition.dns_request("example.com", dns_type="A")
).respond_with_dns(
DnsResponse(
answer_records=[DnsRecord.a_record("example.com", "127.0.0.1")],
response_code="NOERROR"
)
)
require 'mockserver-client'
include MockServer
client = MockServer::Client.new('localhost', 1080)
client.when(
HttpRequest.dns_request('example.com', dns_type: 'A')
).respond_with_dns(
DnsResponse.new(
answer_records: [DnsRecord.a_record('example.com', '127.0.0.1')],
response_code: 'NOERROR'
)
)
import mockserver "github.com/mock-server/mockserver-monorepo/mockserver-client-go/v9"
client := mockserver.New("localhost", 1080)
client.Upsert(mockserver.Expectation{
HttpRequest: &mockserver.HttpRequest{DnsName: "example.com", DnsType: "A"},
DnsResponse: &mockserver.DnsResponse{
ResponseCode: "NOERROR",
AnswerRecords: []mockserver.DnsRecord{mockserver.ARecord("example.com", "127.0.0.1")},
},
})
The Go client's fluent Request() builder has no DNS-matcher setter yet, so the DNS fields are set directly on the exported HttpRequest struct and sent via Upsert instead of When(...).RespondDns(...).
using MockServer.Client;
using MockServer.Client.Models;
using var client = new MockServerClient("localhost", 1080);
client.When(
new HttpRequest { DnsName = "example.com", DnsType = "A" }
).RespondWithDns(
DnsResponse.Response()
.WithResponseCode("NOERROR")
.WithAnswerRecord(DnsRecord.ARecord("example.com", "127.0.0.1"))
);
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"dnsName": "example.com",
"dnsType": "A"
},
"dnsResponse": {
"answerRecords": [
{ "name": "example.com", "type": "A", "value": "127.0.0.1" }
],
"responseCode": "NOERROR"
}
}'
A non-blank dnsName under httpRequest is what makes an expectation a DNS matcher rather than an HTTP one — it is not a separate top-level JSON field, which is why the matcher is still sent under the httpRequest key.
Rust and PHP currently expose only the dnsResponse action builder (used, for example, with scenario state machines or an expectation built from imported JSON) — their HttpRequest type has no DNS-matcher fields at all yet, so they are not shown as separate tabs above; use the REST API form (or, in Rust, the client's raw JSON upsert) to set dnsName/dnsType/dnsClass directly. Go's HttpRequest struct does carry these fields directly (shown above via Upsert), even though its fluent Request() builder has no setter for them yet.
Supported Record Types
Each answer, authority or additional record (org.mockserver.model.DnsRecord) has a name, type, optional dnsClass (defaults to IN) and optional ttl (defaults to 300 seconds when omitted, as in every example on this page), plus type-specific fields:
| Type | Fields | Java factory | Example value |
|---|---|---|---|
| A | value (IPv4 address) | DnsRecord.aRecord(name, ip) | 127.0.0.1 |
| AAAA | value (IPv6 address) | DnsRecord.aaaaRecord(name, ip) | ::1 |
| CNAME | value (target name) | DnsRecord.cnameRecord(name, cname) | alias.example.com |
| MX | priority, value (exchange) | DnsRecord.mxRecord(name, priority, exchange) | priority 10, mail.example.com |
| SRV | priority, weight, port, value (target) | DnsRecord.srvRecord(name, priority, weight, port, target) | _sip._tcp.example.com |
| TXT | value (text) | DnsRecord.txtRecord(name, text) | v=spf1 -all |
| PTR | value (pointer name) | DnsRecord.ptrRecord(name, pointer) | host.example.com |
A DnsResponse can also set responseCode (for example NXDOMAIN or SERVFAIL to mock a resolution failure) and carry separate authorityRecords and additionalRecords lists alongside answerRecords. See DNS Response Size and Record Limits for the UDP truncation behaviour and encoding failures.
Verifying DNS Requests
DNS queries are logged like any other request, so they can be verified with the same verify(...) API used for HTTP requests:
import static org.mockserver.model.DnsRequestDefinition.dnsRequest;
import static org.mockserver.model.DnsRecordType.A;
import static org.mockserver.verify.VerificationTimes.once;
mockServerClient.verify(
dnsRequest("example.com", A),
once()
);
Querying the Mock
Point a resolver at the DNS mock's host and UDP port, for example with dig:
dig @127.0.0.1 -p 5353 example.com A +short
Or configure it as the resolver for a client under test (for example by running the DNS listener on port 53 and pointing /etc/resolv.conf at it in a container — resolv.conf can't set a port — or a custom Resolver in Java/Go, or dns.setServers([...]) in Node.js) so real DNS lookups in your application resolve against the mock during a test.