[TFUI] Re: [agile-testing] Book Recomendation: Web testing

Phlip <[email protected]> Mon, 21 Aug 2006 07:07:05 -0700
Newsgroups gmane.comp.programming.test-first-user-interfaces
Message-ID <[email protected]>
Glenn Halstead wrote:

> I'll soon be working on a new software test project testing the main
> public facing reservations website for an airline.
>
> I'm quite well experienced at automated testing using perl/tcl but
> it's all been system interfaces rather than user interfaces.
>
> The project is already using Mercury tools (test Director / WinRunner)
> so the tools side is catered for.
>
> I'd appreciate any recommendations for books on general concepts and
> methods of web testing to supplement my existing testing experience.

The following is extracted from the Web chapter of a forthcoming book
on test-first for GUIs. It cites /Extreme Programming for Web
Projects/:

The great thing about the Web is it forces you to build a stratified
architecture. (Contrast, for example, Junior's first attempt at
packing a VB6 form's event handlers full of business logic!)

Each strata should have its own test system, and most tests ought to
execute on the server side of the HTTP link. Some behaviors (DHTML,
JavaScript, CSS, Java Applets, etc.) appear on the client side.

Each layer's tests generally mock the layer closer to the user. The
Representation Layer (the data, logic, and business modules) think its
tests are the server-side GUI Layer. The GUI Layer creates XHTML,
thinking a Web server will transmit it. The Web server broadcasts HTTP
to clients that it thinks are Web browsers. And Web browsers, hosting
the client side of the GUI Layer, create "Document Object Model"
representations with hopes that they will paint into display hardware,
and users will look at them.

At each layer boundary, tests intercept I/O by mocking its protocol.
XHTML Tests sample XHTML directly from the functions that create it.
HTTP Tests (as with HttpUnit) emulate your browser, and stream the
XHTML out of an HTTP server. DOM Tests enslave a real Web browser, and
command it to navigate to your sample pages. Then test manipulate the
objects that DHTML and JavaScript use.

To test a Web project, and especially to test-first it, spend a little
up-front design effort pushing all hard logic down below the
Representation Layer. Most of that code will run headless, permitting
the GUI Layer to shrink down as thin as possible. If they are so thin
they only need Authoring (coding simple display logic without tests),
you are almost done. Write a few XHTML Tests, HTTP Tests, or DOM
Tests, just to prove you can, and to kick-start those modules. Most
web site development consists of authoring and reviewing content.

The more dynamic your client-side appearance and behavior, the more
tests you need on the browser-side.

    Minimize System Diversity
Web apps require a mix of programming languages, scripts, systems, and
platforms. Make sure a development workstation can hold an image or
miniature version of the entire project, from database to browser.
This enables programmers to experiment with any part.

Write most tests in the language most convenient for the testee.
Preferably the same language, but sometimes that's impossible. When
you edit, and hit the One Test Button, the module-level tests evaluate
in the common language. But, at need, test cases may shell to
command-lines that run more tests in a different language.

For example, consider XSLT that converts XML into XHTML. You could
write tests in XSLT, but if most of your logic is in Java then you
will have trouble changing your mindset, and the test fixtures,
between the two languages. So, write tests in Java language, and use
an XSLT interpreter to produce the XHTML. Then test the XHTML using
XPath (for "Parsed Fuzzy Matches"), to demonstrate that the XSLT
produced the correct fields. XPath queries can find target nodes
insensitive to their surrounding details.

    XHTML Tests
Most web tests need only assert that lower layers generate correct
HTML with useful contents. The book /Extreme Programming for Web
Projects/, by Doug Wallace, Isobel Raggett, and Joel Aufgang, provides
very good advice to resolve duplication between the many modules that
form a web application. Their Prime Directive: Convert all data into
XML, author all HTML markup inside XSLT, and transform them together
at the last moment to produce each page.

Not all HTML projects are content-rich data-driven public web sites.
The book /Test First User Interfaces/ can only recommend that all
output be XHTML, regardless of its source. WebXP complies with TFUI
when the XSLT enforces XHTML output:

      <xsl:output method="xml" media-type="text/html"
           standalone="no" omit-xml-declaration="yes"
           encoding="UTF-8"/>

XHTML Tests show XPath seeking expected values inside XHTML.

WebXP's Prime Directive, XML for data and XSLT for markup, provides a
lot of incidental testing at very low cost. The act of parsing also
tests. The book also describes a healthy lifecycle for incrementally
adding and reviewing a site's esthetic content (its verbiage and
graphics). "At all times a complete working site can be browsed in
entirety without errors." That should sound familiar to any
practitioner of Test-Driven Development.

    Mock the Server
Each TFUI development effort begins in a tricky spot. Your project
must learn to use test-first, and not your platform's wizard or its
web server, typically without support from your GUI Toolkit's
documentation.

Keeping the web server itself out of your tests provides many
efficiencies. The test cases are easy to write and fast to run when
they obey the server's predefined protocol.

"Common Gateway Interface" is the most common web server scripting
layer, so we must bootstrap a new sample project, to see how it's
done. We start with Perl because that's the most common CGI
implementation (and its much easier to crack than some!).

This script squeezes two modules together - a GuiLayer, and its test,
called main:

    #!/usr/bin/env perl -w

    use strict;  #  don't leave home without it
    use CGI;
    use Test::Unit::TestRunner;
    use XML::XPath;

    package GuiLayer;

        sub processRequest
        {
            my $self = shift;
            my $cgi = shift;

            my $payload = $cgi->param("payload");

            return $cgi->html(
                         $cgi->body("This page says $payload")
                         );
        }

    package main;
        use base qw(Test::Unit::TestCase);

        sub test_verify_page_contents {
            my $self = shift;

        # make CGI think a web browser called it to build a page

            $ENV{'REQUEST_METHOD'} = 'GET';
            $ENV{'QUERY_STRING'} = 'payload=Daddy+Warbucks';
            my $cgi = CGI->new();

        # build the page

            my $response = GuiLayer->processRequest($cgi);

        #  parse the page's contents

            my $xp      = XML::XPath->new(xml => $response);
            my $payload = $xp->find('/html/body/text()');

        #  check our payload influenced the page

            $self->assert_matches(qr/Daddy Warbucks/, $payload);
        }

    my $test = Test::Unit::TestRunner->new;
    $test->start('main');  #  Test Collector pattern

The test makes $cgi and GuiLayer think a web browser requested its
page, obeying an URL such as:

http://localhost/cgi-bin/whatever.pl?payload=Daddy+Warbucks

CGI passes data between a web server and a script by packing it all
into environmental variables. Perl's CGI library permits us to spoof
these data using by passing a string or a map into its constructor:
CGI->new( "payload=Daddy+Warbucks" ), or CGI->new({ payload => 'Daddy
Warbucks' }). I pushed the variables directly into Perl's @ENV
representation of the OS's environmental variables. That technique can
port to any CGI platform.

If your QUERY_STRING must contain a more complex URL, remember to use
URLEncode() to escape any non-ASCII parameters. I represented a space
as its common URL replacement, +.

A normal CGI script would call print GuiLayer->processRequest($cgi).
Our test intercepts the XHTML return value, and parses it with our
favorite utility, XPath. Then assert_matches() checks that it contains
our sample string. That Regular Expression Match, per page 42, could
have been arbitrarily complex.

The GuiLayer module depends on no web server, only $cgi, an object
that's easy to mock. If GuiLayer used any lower modules, the ones
containing business logic would naturally avoid $cgi.
(Thanks to Tony Byrne, on the TDD mailing list, for seeding this topic.)

    Temporary Visual HTML Inspections
If our Perl test sample had been more complex, we might need to
visually inspect the XHTML it produced. If $response contained that
XHTML, these lines would lead to a reveal() fixture:

            open(TEMP, '>c:/temp/temp.html');
            print TEMP $response;
            close(TEMP);
            system('start c:/temp/temp.html');

"start" depends on your MS Windows CMD.EXE, so you may need some other
system to view the page, such as "konqueror".

The heart of the TFUI cycle is a test-side function called reveal().
You call it from any test case, and it stops the tests and displays a
GUI in its currently tested state. You must create a reveal() function
for each GUI architecture you use, and you should productize it enough
that you can temporarily add it to any function without stopping to
think about details like temporary folders.

Your HTML may pull in graphics and scripts from other files. One
Hristo Deshev, from the TFUI mailing list, reminds us a temporary HTML
file might not be able to see them, so use this tag: <base
href="http://someUrl.com/" />. Adding that to your page will base all
the relative path calculations on the URL.

    HTTP Tests
A package that emulates a web browser, following the W3C
recommendations, can keep all the real browsers honest. The Java
library HttpUnit, by Russell Gold, at http://www.httpunit.org/,
simulates a browser so well that one can develop server-side features
using test-first on the client side. Don't make that a habit.

Here's a sample of HttpUnit in action, testing the web site that keeps
so many programmers sane;

http://c2.com/cgi/wiki?HttpUnitTutorial

HttpUnit might be the best place for you to start, to retrofit tests
into legacy code. It has the benefits of driving a GUI through its
scenarios, and soak-testing the back-end logic, without the drawbacks
of driving a web browser. Use Watir to drive a web browser and test
the "last mile" of JavaScript, AJAX, DHTML, etc.

-- 
  Phlip
  http://c2.com/cgi/wiki?ZeekLand  <-- NOT a blog!!


To unsubscribe, email:
TestFirstUserInterfaces-unsubscribe-hHKSG33TihhbjbujkaE4pw@public.gmane.org
 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/TestFirstUserInterfaces/

<*> To unsubscribe from this group, send an email to:
    TestFirstUserInterfaces-unsubscribe-hHKSG33TihhbjbujkaE4pw@public.gmane.org

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/