
Automated, Javascript, Remoting, UnitTest, TDD, Test, WebService, XMLHttpRequest
Dave is creating a trading application, and on the server there are services to give quotes and accept orders. To help develop and test the web service, he builds a suite of Service Tests. One test, for example, submits an order and checks the database registered it. These tests are automated and re-executed every time the project changes.
Build up automated tests of web services, using HTTP clients to interact with the server as the browser normally would. The browser-server interaction of an Ajax App is usually a sequence of “XMLHttpRequest Call”s. That's fortunate, because testing the service is usually as easy as simulating the browser - passing a certain request and checking the response. Sometimes, verification might also involve checking what happened on the server, e.g. a database state change or a message to an external system.
The test itself can be built in any language and testing framework you like, because it's completely decoupled from both the browser and the server. The only practical constraint is that you should be able to run it from a script, to allow for continuous integration. Many languages provide an HTTP client library, so it's easy to build a test pass requests to the server and make assertions against the response. Indeed, there are client frameworks like HTTPUnit specifically for the purposes of testing web apps. They're typically used for testing conventional applications, where the response contains an entire page, but they work fine for the terse responses usually provided by web services.
A “RESTful Service”, in particular, should be straightforward to test because: (a) it will usually output structured responses which are easily parsed, and (b) there won't be any conversational state to set up and track. A service that outputs an “HTML Message” makes tests a bit more fragile; passing in 5+5 will always let you assert 10 as the “Plain-Text Message”, but not always The <span class="strong">answer</class> is <span class="surprising">10<span>!!! if an “HTML Message” is used.
: Net:HTTP is an HTTP client library for Ruby, shipping with the standard distribution. It's used in the refactoring illustration below.
Jakarta HTTPClient is a richly-featured HTTP client framework for Java.
Simon Willison's HTTPClient is a basic HTTP client framework for Perl.
The Basic Ajax Pattern Reader uses some “Simulation Service”s to get information from the server. A Service Test was first created against the “Simulation Service”, and once this passed, the test was used to drive the design of the real services. The Solution mentioned that the programming language of the HTTP client is completely independent of the server or browser languages, and that's not just theoretical, since some languages (e.g. Ruby, Perl) are particularly well-suited to string manipulation. To prove the point, the example here uses Ruby's Net::HTTP library.
The service being tested is patternSummary.phtml, a pattern text provider which accepts a pattern name and outputs its solution. The test case is very basic - it just requests the Slider pattern and checks the output matches a simple regular expression:
require "test/unit"
require "net/http"
class PatternServiceTest < Test::Unit::TestCase
def test_slider
sliderResponse = grabPattern("Slider");
regex = /^\s*<h1><a\ href=\".*?\">Slider<\/a><\/h1>\s*\
<span\ class=\"summary\">.+?<\/span>.+
/mx;
assert_match(regex, sliderResponse.body);
end
...
def grabPattern(patternName)
session = Net::HTTP.new('ajaxlocal', 80);
response = session.get("/run/reader/logging/realService/" +
"patternSummary.phtml?patternName=" + patternName);
assert_equal("200", response.code);
return response;
end
end
You can sometimes start creating a test against a “Simulation Service”, and gradually refactor it into a real service, while evolving the test as well.
A “Browser-Side Test” is a good complement to a Service Test, since the former tests browser behaviour while the latter ensures the server will support the browser in the correct way.