[
Installation ]
[
Recording and Running ]
Editing
[
Recipes ]
[
Command Line ]
Editing Tests
MaxQ test scripts are simply Jython
scripts that get MaxQ to pretend to be a web browser.
Jython is an implementation of the popular
Python language for use in Java
programs.
Almost all standard Python features and much of the standard
libraries work in Jython without code changes. If you want to learn
how to write Python/Jython/MaxQ scripts, see the
Python documentation.
Anatomy of a MaxQ Standard Test Script
When you record a script, the output will look something like this:
(Warning: This section needs to be updated.)
1: # imports
2: from com.bitmechanic.maxq import HttpTestCase, EditorPane
3: from junit.textui import TestRunner
4: from java.util import *
5:
6: # defintition of test class
7: class MaxQTest(HttpTestCase):
8: def __init__(self):
9: HttpTestCase.__init__(self, "")
10:
11: def runTest(self):
12: self.get("http://www.google.com/")
13: self.assertEquals(200, self.getResponse().getStatusCode())
14:
15: self.get("http://www.google.com/images/logo.gif")
16: self.assertEquals(304, self.getResponse().getStatusCode())
17:
18:
19: list = [
20: ("hl", "en"),
21: ("q", "testing+tools"),]
22: self.get("http://www.google.com/search", list)
23: self.assertEquals(200, self.getResponse().getStatusCode())
24:
25: ##########################################
26:
27: # Code to load and run the test
28: test = MaxQTest()
29: test.runTest()
The script is simply python code. But if you're like me, you have no idea
how python works. The table below should help clarify what this code means
from a Java perspective.
| lines |
purpose |
| 1 |
comment. all lines starting with # are comments. |
| 2-4 |
import statements. notice how we can import Java packages into the
python namespace. these classes must be in the CLASSPATH of the
script that starts MaxQ (e.g. maxq.bat), so if you wish to use
your own classes, make sure to edit the CLASSPATH accordingly. |
| 7 |
class declaration. this line tells python that the rest of the
block is part of a class named MaxQTest that subclasses
the Java class HttpTestCase. note that Jython lets us
transparently subclass Java classes from python code. that was the
primary reason python was chosen as the scripting language. |
| 8-9 |
class constructor. calls the constructor of our parent class.
note that python uses the word self to denote the current
instance of the class. it's equivalent to this in Java.
you shouldn't need to edit this section.
|
| 11 |
start of our test method. MaxQ records the session as one long
test function. you can break up these function into pieces if you
wish. |
| 12 |
we request Google's home page. get() is a method in the
HttpTestCase class that we subclassed. |
| 13 |
run a JUnit assertion. MaxQ automatically inserts an assertion that
verifies that the HTTP response code is the same as the one it
received when the test was recorded. |
| 19-21 |
when we submitted the search form at Google, MaxQ created a ArrayList
in the script, and filled in the variables that were sent in the
QUERY_STRING. similar code would be written if this were a POST. |
| 22 |
note the second argument to get() that passes in the list object.
since it's a GET request, those variables will be formed into a
QUERY_STRING |
| 25 |
comment line used to visually denote the end of our test class |
| 28 |
this line instantiates our test class. this is the first real line
of code that executes during test playback
(besides the import statements) |
| 29 |
invokes our test method. note that there's _no_ magic going on here.
this test script stands alone. what makes the script useful is that
it's subclassing the JUnit TestCase class, and has a Java HTTP library
sitting behind it. but at this point control flow goes straight to
line 11. you could rename the method name in line 11 and 29, and as
long as they matched, the script would still run. |
OK, so now what? Well, once the script has been recorded, you can pretty
much edit it to your choosing. Consider these modifications:
11: def runTest(self):
12: print "I'm requesting the Google home page!"
13: self.get("http://www.google.com/")
14: self.assertEquals(200, self.getResponse().getStatusCode())
add another assertion
11: def runTest(self):
12: self.get("http://www.google.com/")
13: self.assertEquals(200, self.getResponse().getStatusCode())
14: self.assertTrue(self.responseContains("Make Google Your Homepage"))
HttpTestCase class
All MaxQ tests have HttpTestCase as a base class. Among other things,
HttpTestCase gives MaxQ tests the get() and post()
functions that they use to retrieve web pages.
HttpTestCase is a subclass of the JUnit
TestCase
class, which can be useful if you want to run MaxQ test scripts in a test
harness. You can call any methods that are in the TestCase class, although
they can lead to long, difficult-to-read Java exception error messages
if your script does not run correctly.
In addition to get() and post(), HttpTestCase defines utility methods:
| responseOK() |
throws Error if response not 200, 302, or 304 |
| responseContainsURI(uri) |
Returns whether the response contain the supplied URI. Useful to
check for redirects. |
| responseContains(text) |
Returns whether the response contains the supplied string. |
| printResponse() |
Prints HTML response to STDERR. |
| getResponseCode() |
Returns the integer response code. e.g. 200, 302. |
| getResponseHeader() |
Returns a dictionary of the lines in the response header. e.g.
if str(self.getResponseCode())[-3] = '3':
print "Redirected to " + self.getResponseHeader()['Location'] |
| getResponse() |
Returns the full text of the response |
| scriptArg() |
Returns the value of any --script-arg paramater |
| userConfirm(String msg) |
Shows an OK/Cancel message box. Returns true if the user clicked OK.
|
| userInput(prompt) |
Shows prompt in a message box and waits for input.
If the user clicks Cancel then None is returned. If the user clicks
OK then any text entered is returned. |
| setCharset(charset) |
Sets the character set used in POST requests, in the Content-Type header.
e.g. self.setCharSet('UTF-8') |
As well as calling methods of the base classes, you can override them:
def setUp(self):
# Code to be run before tests.
...
def tearDown(self):
# Code to be run after tests.
...