Generating unit tests
7.6 T ECHNIQUE : THE TEST ROBOT GENERATOR
When it comes to user interfaces, web applications are easier to test than desktop appli-cations. To test a desktop application through the user interface, you need a framework that can shield your test code from the system-level keyboard and mouse event genera-tion used to implement the test. To test a web applicagenera-tion through the user interface, all you need is an HTTP access library.
Applications that walk through a web user interface are called robots. An example robot for an online auction system may follow these steps:
• Fetches the main page and checks for the login form.
• Sends the login information via a POST.
• Gets and stores the session cookie.
• Requests the main page and parses the HTML to find the available items.
• Iterates through each item and fetches its page. It checks each page for the proper
Generator Invocation
Templates
Test Code Test Framework Random
Generator Data
Templates
Test Data DataPool
Test Definition
Figure 7.6 How the test data generator feeds the sequential test generator
TECHNIQUE: THETESTROBOTGENERATOR 155 Each of these is a complete system test that makes use of the entire technology stack, from the database access layer through the persistence layer and the user interface.
If a robot says your system is responding properly, then you are likely in good shape.
Robots have other uses as well:
• Stress-testing an application by sending lots of requests in a short period of time
• Random “monkey-testing” an application by fetching pages out of order
• Argument-testing an application by sending invalid or missing arguments from the POST or GET
When building robots you should insulate your test code from the HTTP transit code required to get the page, post requests, or parse responses. The generator in section 7.5.1 builds interface wrappers that can be used by robots to post data to the web application or to fetch pages and parse their data.
7.6.1 Roles of the generator
Test systems become a source of infinite features once engineers understand that they no longer need to tediously hand-test their code. To keep that from happening, it’s ideal to lay down a set of responsibilities for the test system and its generator. The test robot generator has one main responsibility: building automated tests for the pages built to the predictable standards of the web user interface for the target application.
Here we’ve listed those tasks the generator does not take responsibility for:
• Documenting the tests.
• Testing interfaces that extensively use client-side functionality, such as JavaScript or Flash; the automated testing agents cannot access or test that code because the test agent is not a complete web browser.
With these guidelines in hand, you can continue on to designing the architecture of the generator.
7.6.2 Laying out the generator architecture
The web generator in Figure 7.7 builds interface wrappers for your robots. The wrapper hides the web transit logic from the robot, leaving the robot free to simply specify which pages are to be called, with what arguments, and in what order. Multiple robots, serving different purposes, can use these wrappers. The robots may load data, stress test, or bridge between the application and other technologies, such as instant messaging.
Using page definitions, the generator builds wrappers that handle posting argu-ments and then parsing the returned HTML from the server. The page definition file must have this data about each page:
• The page URL
• The names and types GET or POST arguments
• The structure of the data returned on the page
You can make it easy for the robots to find what they need by adding comments to the pages they will read. You can also bracket the important data on the page in DIV or SPAN tags, which are invisible to the user but are easily found using regular expres-sions. By targeting the page parser on specific DIV or SPAN tags within the page, you ensure that the robot will not break if the page structure changes for aesthetic reasons.
Let’s go back to the online auction system we discussed earlier. The first thing the robot does after logging in is to see what is on sale. Here is some example HTML for the “What is on sale?” page:
<html><head><title>What is on sale</title><head>
<body>
Here is what is on sale today (<div id="today">1/23/03</div>):<br><br>
<table>
<tr><td>Name</td><td>Price</td></tr>
<tr>
<td><a href="item.cgi?id=2601"><div id="name_2601">Java In A Nutshell</
div></a></td>
<td><div id=”price_2601">$26.95</div></td></tr>
<tr>
<tr>
<td><a href="item.cgi?id=2602"><div id="name_2602">Perl In A Nutshell</
div></a></td>
<td><div id="price_2602">$35.00</div></td></tr>
<tr>
<td>
If we use a regular expression that reads the DIV tags and gets the ID and contents, we get the following ordered pairs of information:
today 1/23/02
name_2601 Java In A Nutshell cost_2601 $26.95
name_2602 Perl In A Nutshell cost_2602 $35.00 Figure 7.7 A generator that builds robots for testing
FINDINGATOOLTODOITFORYOU 157 This is the data that is important to the robot. The rest of the page is aesthetic information, which is important but not for this type of testing. The DIV tags insulate our robot from any changes to the aesthetic look of the page. The graphic designers can make any changes they like, so long as the DIV tags remain.
Next we’ll look at how the robot goes about its work.
7.6.3 Processing flow
The web robot page wrapper generator follows these steps:
● Reads in the page definitions and stores them locally.
● Goes through each page and follows these steps:
❍ For a form page, builds a POST or GET wrapper to fill in the form variables.
❍ For a report page, builds a page-parsing wrapper that reads and returns the contents of the SPAN or DIV tags.
Once this process is completed, you will have a set of wrappers that your robot can use to walk the site and that provides a level of abstraction between your robot logic and the layout of your site.
7.6.4 Generators for robots
Our wrapper generator merely built the interface wrappers for web pages that allows robots to walk our application with ease. Another type of generator can generate the robots themselves, using a dictionary of user actions. Here are two open source genera-tors that build web robots:
• Sight is a toolkit for generating robots (http://jsight.sourceforge.net/index_SF.htm).
• Roboweb is a toolkit for building web robots (http://sourceforge.net/projects/
roboweb/).
7.7 F
INDING A TOOL TO DO IT FOR YOUUnit tests fit within test harnesses. These harnesses provide reporting capabilities, test data generation capabilities, as well as other utilities useful in building unit tests. The following list shows some off-the-shelf testing tools for unit tests:
• Segue (www.segue.com) provides a set of programmable testing tools that can test Windows desktop and web application software.
• JUnit (www.junit.org/) is a unit test framework for Java.
• CppUnit (http://cppunit.sourceforge.net/) is a unit test framework for C++.
• HttpUnit (http://httpunit.sourceforge.net/) tests web applications through the user interface using HTTP.
• LWP::UserAgent (www.perldoc.com/perl5.6.1/lib/LWP/UserAgent.html) is a Perl library for writing HTTP robots.
Test robot generator
• CsUnit (www.csunit.org) is a unit test framework for Microsoft’s .NET tech-nology stack.
• PHPUnit (http://wiki.berlios.de/index.php?PhpUnit) is a framework for testing PHP applications.
• PyUnit (http://pyunit.sourceforge.net/pyunit.html) is a unit testing framework for Python.
• DataFactory (www.quest.com/datafactory/) from Quest Software connects directly to a database to populate it with test data.
7.8 D
ESIGN TIPSHere are some suggestions for designing your code so that you can build testing tools using generators:
• For interface code, consistency is king. Preferably all of your pages will be gener-ated to make sure that GET and POST arguments are named consistently and processed the same way across the interface.
• For APIs, make sure your accessors and instance variables all use the same naming conventions. Also, your return types should be standardized across the interface.
• Use JavaDoc or special comments that the test case builder can use to configure itself to handle special API cases such as Singletons.
7.9 S
UMMARYThe code base of any application is a valuable asset to the individual or company who owns or maintains the application. To maintain the code base long-term, software engi-neers have started to refactor code continuously. The term refactoring refers to the disci-pline of reworking the architecture of the application to match the current needs. As applications progress, you often find that the design decisions made in the beginning of the project are no longer valid, which means you have to refactor the code so that it will elegantly solve the current problem.
Unit tests are central to refactoring. If you have unit tests that test your component using test data and responses that match the current requirements, you can change the implementation of the component at will. As long as the output of the component still passes the unit tests, you can be reasonably sure the code is correct.
The key is having the unit tests in the first place. Having unit tests means that you can refactor. Refactoring means that you can keep the code base fresh with constant maintenance.
Using code generation for unit tests makes it easy to maintain and extend your unit tests. In this way, you avoid the common pitfall of not maintaining the unit tests or even failing to create them in the first place.
In the next chapter, we’ll tackle a generator that embeds SQL into another language.
159
C H A P T E R 8