Automated Testing With WWW::Mechanize
Automated Testing With WWW::Mechanize
WWW::Mechanize
Copyright 2004, Andy Lester
Automated testing
philosophy
Why test?
Humans make mistakes
Bugs cost time & money
Bugs are demoralizing
Testing shows that your code works
At least in the cases that you're testing
Why automated
testing?
Humans hate testing. Computers don't.
Instantly verify changes haven't broken code
Regularly verify all code
More tests don’t make the computer grumble
Automated testing
philosophy
You are human
Testing is an investment
Test for now
Test for the future
Test constantly
You are human
You're good, but not that good
Your coworkers are human, too
Machines work, humans think
Machines are good at repetitive tasks.
A cron job will never blow off its tasks because
they're boring.
Test for the future
Testing will detect breakage in the future
(at least if you actually run the tests)
99.99% of the time, the test runs fine
This is not a waste
Proves that your code still works as you wrote it.
Eliminate future stress and frustration!
How Perl handles
testing
• Test::Harness runs your
.t files
Bummer if it fails:
not ok 1 - The holy trinity
# Failed test (stooges.t at line 8)
my @stooges = get_stooges();
cmp_ok( scalar @stooges, ">=", 3,
"We'll allow Shemp" );
Return values of ok()
ok() et al return booleans
Use to know at runtime a test's status
die if a critical failure means all others will fail, oo
use_ok( 'HTML::Lint' );
my $linter = new HTML::Lint;
isa_ok( $linter, 'HTML::Lint' );
ok 1 - use HTML::Lint;
ok 2 - The object isa HTML::Lint
TODO blocks
When you don't have the code done yet, you can
still have tests.
T::H doesn't count these as failures
You'll be told if they unexpectedly succeed
TODO: {
local $TODO = "read_minds() not done";
is( $nrows, 100, "Should have 99 rows, plus the one we added" );
Make autonomous test
files
Don't make test files rely on each other
Tests should clean up after themselves
You can't rely on the order that test files get run.*
# Errors:
# (184:42) <IMG> tag has no HEIGHT and WIDTH attributes.
WWW::Mechanize
Subclass of LWP::UserAgent
Acts like a web browser
Has a back() function
Handles forms and fields for you
Many handy convenience functions
WWW::Mechanize
Wraps up web and form pages
Handles proxies, agent strings, etc
my $mech = new WWW::Mechanize;
$mech->agent( "TestBot/1.0" );
$mech->get( "http:://foo.com" );
if ( $mech->success ) {
print $mech->content;
} else {
print $mech->response->error_as_HTML;
}
Get a page
Get a page with Mech
use WWW::Mechanize;
my $m = WWW::Mechanize->new();
$m->get( "http://plainblack.com/" );
print $m->title, "\n";
$ ./fetch.pl
Plain Black, makers of WebGUI - Home
Accessing links
links() returns array of all links
Each link is an object containing:
The text of the link
The raw URL
The absolute URL
Contents of the NAME attribute
Links also include <FRAME> tags.
Check title and links
Check title & links
my $m = WWW::Mechanize->new();
$m->get( "http://www.plainblack.com/" );
print "Title: ", $m->title, "\n";
print $_->text, " --> ", $_->url, "\n"
for $m->links;
$ ./links.pl
Title: Plain Black, makers of WebGUI - Home
Plain Black --> http://www.plainblack.com/home
Store --> http://www.plainblack.com/store
WebGUI Users --> http://www.plainblack.com/wg
Write a test file
title.t
Make sure your title is correct
use Test::More tests => 2;
use WWW::Mechanize;
my $m = WWW::Mechanize->new() or die;
$m->get( "http://plainblack.com/" );
ok( $m->success, 'Fetched OK' );
like( $m->title, qr/Plain Black/ );
Running title.t
Running title.t
$ prove title.t
title....ok
All tests successful.
Files=1, Tests=2, 2 wallclock secs
( 0.70 cusr + 0.08 csys = 0.78 CPU)
$ prove -v title.t
title....1..2
ok 1 - Fetched OK
ok 2 - Right title
All tests successful.
Files=1, Tests=2, 2 wallclock secs
( 0.60 cusr + 0.12 csys = 0.72 CPU)
Follow a link
The follow_link() method takes a string to match,
or a number of the link to follow.
$a->back();
ok( $m->success, "Went back" );
}
Handling forms
Parsed them automatically on get()
Each form represented by a HTML::Form object
Forms specified by number or name
Fields specified by name
Fill out a form
# Get http://plainblack.com/search, then...
$a->form_number(1);
$a->field( "as_q" => "Perl" );
$a->submit;
like( $a->content,
qr/Results \d+ - \d+ of about \d+/,
"Got search results back" );
Submit the form
Two ways to submit a form
$a->submit(); # No "click"
$a->click("name"); # "click" the "name" button
$ weblint http://www.plainblack.com
http://www.plainblack.com (184:42) <IMG> tag has no HEIGHT and
WIDTH attributes.
Using HTML::Lint
Create an HTML::Lint object
Set your parms
Feed it text or a filename
Handle the errors programmatically
Test::HTML::Lint
Wraps HTML::Lint in Test::* framework
Creates the HTML::Lint object for you
Can take an object you create
Allows you customizations
Test::HTML::Lint in
action
Validate HTML on the site
use Test::More tests=>2;
use Test::HTML::Lint;
use WWW::Mechanize;
my $m = WWW::Mechanize->new;
$m->get( "http://www.plainblack.com/" );
ok( $m-success, "Fetched OK" );
html_ok( $m->content, "Home page valid HTML" );
Test::HTML::Lint in
action
Running the HTML checker
ok 1 - Fetched OK
not ok 2 - Home page valid HTML
# Failed test (foo.pl at line 8)
# Errors: Home page valid HTML
# (30:1) Unknown attribute "rightmargin" for tag <body>
# (30:1) Unknown attribute "bottommargin" for tag <body>
# Looks like you failed 1 tests of 2.
my $lint = HTML::Lint->new;
$lint->only_types( HTML::Lint::STRUCTURE );
html_ok( $lint, $m->content );
no_link($HTML, "http://www.pearl.com",
"We have no embarassing typos");
link_ok($HTML, qr"http://[a-z]+\.perl.com",
"We have a link to perl.com");
Testing more than just
your website
Testing more than your
code
As long as you can call ok(), you can test anything
using Perl.
Project-wide rules
Database validity
Web pages
Adequate disk space
Anything else at all
Where to Get More
Information
• http://qa.perl.org
• Test::Tutorial
• Test::WWW::Mechanize