Login | Register
My pages Projects Community openCollabNet
[ 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:

    add a print statement
    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.
      ...