Sawyer X > Test-DNS > Test::DNS



Annotate this POD

View/Report Bugs
Module Version: 0.13   Source  


Test::DNS - Test DNS queries and zone configuration


version 0.13


This module helps you write tests for DNS queries. You could test your domain configuration in the world or on a specific DNS server, for example.

    use Test::DNS;
    use Test::More tests => 4;

    my $dns = Test::DNS->new();

    $dns->is_ptr( '' => '' );
    $dns->is_ptr( '' => [ '', '' ] );
    $dns->is_ns( '' => [ map { "ns$" } 1 .. 4 ] );
    $dns->is_a( '' => '' );



Test::DNS allows you to run tests which translate as DNS queries. It's simple to use and abstracts all the difficult query checks from you. It has a built-in tests naming scheme so you don't really have to name your tests (as shown in all the examples) even though it supports the option.

    use Test::DNS;
    use Test::More tests => 1;

    my $dns = Test::DNS->new( nameservers => [ 'my.dns.server' ] );
    $dns->is_ptr( '' => 'my_new.mail.server' );

That was a complete test script that will fetch the PTR (if there is one), warns if it's missing one (an option you can remove via the warnings attribute) and checks against the domain you gave. You could also give for each test an arrayref of expected values. That's useful if you want to check multiple values. For example:

    use Test::DNS;
    use Test::More tests => 1;

    my $dns = Test::DNS->new();
    $dns->is_ns( 'my.domain' => [ '', '' ] );
    # or
    $dns->is_ns( 'my.domain' => [ map { "ns$" } 1 .. 5 ] );

You can set the follow_cname option if your PTR returns a CNAME instead of an A record and you want to test the A record instead of the CNAME. This happened to me at least twice and fumbled my tests. I was expecting an A record, but got a CNAME to an A record. This is obviously legal DNS practices, so using the follow_cname attribute listed below, the test went with flying colors. This is a recursive CNAME to A record function so you could handle multiple CNAME chaining if one has such an odd case.

New in version 0.04 is the option to give a hashref as the testing values (not including a test name as well), which makes things much easier to test if you want to run multiple tests and don't want to write multiple lines. This helps connect Test::DNS with freshly-parsed data (YAML/JSON/XML/etc.).

    use Test::DNS;
    use YAML 'LoadFile';
    use Test::More tests => 2;

    my $dns = Test::DNS->new();
    # running two DNS tests in one command!
    $dns->is_ns( {
        'first.domain'  => [ map { "ns$_.first.domain"  } 1 .. 4 ],
        'second.domain' => [ map { "ns$_.second.domain" } 5, 6   ],
    } );

    my $tests = LoadFile('tests.yaml');
    $dns->is_a( $tests, delete $tests->{'name'} ); # $tests is a hashref


This module is completely Object Oriented, nothing is exported.



Same as in Net::DNS. Sets the nameservers, accepts an arrayref.

    $dns->nameservers( [ 'IP1', 'DOMAIN' ] );


Do you want to output warnings from the module (in valid TAP), such as when a record doesn't a query result or incorrect types?

This helps avoid common misconfigurations. You should probably keep it, but if it bugs you, you can stop it using:


Default: 1 (on).


When fetching an A record of a domain, it may resolve to a CNAME instead of an A record. That would result in a false-negative of sorts, in which you say "well, yes, I meant the A record the CNAME record points to" but Test::DNS doesn't know that.

If you want want Test::DNS to follow every CNAME recursively till it reaches the actual A record and compare that A record, use this option.


Default: 0 (off).


is_a( $domain, $ips, [$test_name] )

Check the A record resolving of domain or subdomain.

$ip can be an arrayref.

$test_name is not mandatory.

    $dns->is_a( 'domain' => 'IP' );

    $dns->is_a( 'domain', [ 'IP1', 'IP2' ] );

is_ns( $domain, $ips, [$test_name] )

Check the NS record resolving of a domain or subdomain.

$ip can be an arrayref.

$test_name is not mandatory.

    $dns->is_ns( 'domain' => 'IP' );

    $dns->is_ns( 'domain', [ 'IP1', 'IP2' ] );

is_ptr( $ip, $domains, [$test_name] )

Check the PTR records of an IP.

$domains can be an arrayref.

$test_name is not mandatory.

    $dns->is_ptr( 'IP' => 'ptr.records.domain' );

    $dns->is_ptr( 'IP', [ 'first.ptr.domain', 'second.ptr.domain' ] );

is_mx( $domain, $domains, [$test_name] )

Check the MX records of a domain.

$domains can be an arrayref.

$test_name is not mandatory.

    $dns->is_mx( 'domain' => 'mailer.domain' );

    $dns->is_ptr( 'domain', [ 'mailer1.domain', 'mailer2.domain' ] );

is_cname( $domain, $domains, [$test_name] )

Check the CNAME records of a domain.

$domains can be an arrayref.

$test_name is not mandatory.

    $dns->is_cname( 'domain' => 'sub.domain' );

    $dns->is_cname( 'domain', [ 'sub1.domain', 'sub2.domain' ] );

is_txt( $domain, $txt, [$test_name] )

Check the TXT records of a domain.

$txt can be an arrayref.

$test_name is not mandatory.

    $dns->is_txt( 'domain' => 'v=spf1 -all' );

    $dns->is_txt( 'domain', [ 'sub1.domain', 'sub2.domain' ] );

is_record( $type, $input, $expected, [$test_name] )

The general function all the other is_* functions run.

$type is the record type (CNAME, A, NS, PTR, MX, etc.).

$input is the domain or IP you're testing.

$expected can be an arrayref.

$test_name is not mandatory.

    $dns->is_record( 'CNAME', 'domain', 'sub.domain', 'test_name' );


Moose builder method. Do not call it or override it. :)


The hash format option (since version 0.04) allows you to run the tests using a single hashref with an optional parameter for the test_name. The count is no longer 1 (as it is with single tests), but each key/value pair represents a test case.

    # these are 2 tests
    $dns->is_ns( {
        'first.domain'  => [ map { "ns$_.first.domain"  } 1 .. 4 ],
        'second.domain' => [ map { "ns$_.second.domain" } 5, 6   ],
    } );

    # number of tests: keys %{$tests}, test name: $tests->{'name'}
    $dns->is_a( $tests, delete $tests->{'name'} ); # $tests is a hashref







Sawyer X, <xsawyerx at>


Please report any bugs or feature requests to bug-test-dns at, or through the web interface at I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.


You can find documentation for this module with the perldoc command.

    perldoc Test::DNS

You can also look for information at:



Copyright 2010 Sawyer X.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See for more information.


  Sawyer X <>


This software is copyright (c) 2011 by Sawyer X.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

syntax highlighting: