Powered By Smalltalk


Introduction

In a galaxy far, far away...A lone web developer thought it would be great to have a way of testing his web applications. He wanted something easy and simple. SUnit was all of those things, but he could only test his model with it. He wanted to verify data in his web pages without needing a PHD or resorting to regular expressions. He liked the idea of HTML elements beings first class objects not just strings.

Enter SmallHttpUnitTest, the brainchild of Roger Whitney and brought to reality by himself and Blaine Buxton. It was initially designed and implemented at Camp Smalltalk 2004. Right now, it is only available on CincomSmalltalk with plans to port to Squeak (and other platforms).

So, what makes SmallHttpUnitTest different from other Http testing frameworks? Well, it's built on top of SUnit and great pains were taken to make the syntax as simple and as close to html as possible. Also, even though you write your tests in Smalltalk using SUnit, there is no need to have your web application written in Smalltalk as well. In fact, the web application that you're testing could be written in anything including java, php, python, perl, ruby, or anything else you can think of. The designers wanted a flexible framework that could demonstrate the power of Smalltalk and make the simplest HTTP Unit Testing Framework available!

We hope you enjoy testing with it as much as we enjoyed writing it. If you have any suggestions, compliments, or heaven forbid complaints, please feel free to send them to me.

Download

You can get it from the Cincom Public Repository or as a parcel from here.

Examples

Here's a method from a test for Google:
    testClick
    | browser |
    browser := HttpBrowser on: 'http://www.google.com'.
    self assert: (browser title includesText: 'Google').
    browser click: 'Images'.
    self assert:( browser title includesText: 'Google Image Search').
    browser back.
    self assert: browser title text first = 'Google'
The first line in the test basically sets our browser object to a url that will be the starting point of our test.
We can then interrogate the browser object about its current page that it loaded. We can test for what is in the current page, navigate, submit forms, and anything a user would do in a browser.
This first example simply shows us loading the main Google page, and then the user clicking the images button. We then interrogate the browser's current page to make sure it did the right thing.

Let's look at another example:
    testPost
    | browser form |
    browser := HttpBrowser on: 'http://www.google.com'.
    form := browser form action: '/search'.
    form name: 'q' value: 'Blaine Buxton'.
    (form value: 'I''m Feeling Lucky') submit.
    self assert: ( browser includesText: '*Blaine Buxton*').
    self assert: ('*blainebuxton.com*' match: browser currentPage url).
This one looks a lot like the previous example except now we are submitting a form and finding elements in the current page of the browser.
We find the form by sending messages to the browser. When we send the message form to the browser, it returns all of the forms in the current page.
If we then send the message action: '/search' to this collection of forms, it will search this collection for a form with the attribute action with the value of /search.
We can even set attributes to the returned objects and this is what is happening when we send name:value: to the form object.

You can search for elements in the current page by sending a message a unary message (for example, browser form, browser a). You can also search for attributes and their value to use for matching as well.
So, if you think about it, we created a mini language to support succinct testing for html pages!

One last complicated example:
    testNavigation
    | browser |
    browser := self browserClass on: 'http://localhost:8008/seaside/go/counter'.
    self assert: (browser h1 allSatisfy: [:each | each text = '0']).
    self assert: (browser a text includesAllOf: #('++' '--')).

    browser click: [:a | a text = '++'].
    self assert: (browser h1 text includesExactly: #('1')).

    browser click: '++'.
    self assert: (browser h1 text includesExactly: #('2')).

    browser click: '--'.
    self assert: (browser h1 text includesExactly: #('1')).
This one tests the counter example in seaside. As you can see, it's extremely easy to write new tests! If you have any comments, please feel free to email me.

Future Enhancements

  1. Ability to write test skeletons by recording user actions in web browser
  2. Ports to various Smalltalk dialects (namely Squeak)
  3. Making it easier to write tests!

License

Copyright (c) 2004 Roger Whitney, Blaine Buxton

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Feel free to send me email!