aboutsummaryrefslogtreecommitdiff
path: root/vendors/simpletest/docs/en
diff options
context:
space:
mode:
Diffstat (limited to 'vendors/simpletest/docs/en')
-rw-r--r--vendors/simpletest/docs/en/authentication_documentation.html355
-rw-r--r--vendors/simpletest/docs/en/browser_documentation.html447
-rw-r--r--vendors/simpletest/docs/en/docs.css121
-rw-r--r--vendors/simpletest/docs/en/expectation_documentation.html422
-rw-r--r--vendors/simpletest/docs/en/form_testing_documentation.html342
-rw-r--r--vendors/simpletest/docs/en/group_test_documentation.html386
-rw-r--r--vendors/simpletest/docs/en/index.html538
-rw-r--r--vendors/simpletest/docs/en/mock_objects_documentation.html757
-rw-r--r--vendors/simpletest/docs/en/overview.html486
-rw-r--r--vendors/simpletest/docs/en/partial_mocks_documentation.html445
-rw-r--r--vendors/simpletest/docs/en/reporter_documentation.html519
-rw-r--r--vendors/simpletest/docs/en/unit_test_documentation.html431
-rw-r--r--vendors/simpletest/docs/en/web_tester_documentation.html584
13 files changed, 5833 insertions, 0 deletions
diff --git a/vendors/simpletest/docs/en/authentication_documentation.html b/vendors/simpletest/docs/en/authentication_documentation.html
new file mode 100644
index 000000000..8da2a7f9e
--- /dev/null
+++ b/vendors/simpletest/docs/en/authentication_documentation.html
@@ -0,0 +1,355 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest documentation for testing log-in and authentication</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <span class="chosen">Authentication</span>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Authentication documentation</h1>
+ This page...
+ <ul>
+<li>
+ Getting through <a href="#basic">Basic HTTP authentication</a>
+ </li>
+<li>
+ Testing <a href="#cookies">cookie based authentication</a>
+ </li>
+<li>
+ Managing <a href="#session">browser sessions</a> and timeouts
+ </li>
+</ul>
+<div class="content">
+
+ <p>
+ One of the trickiest, and yet most important, areas
+ of testing web sites is the security.
+ Testing these schemes is one of the core goals of
+ the SimpleTest web tester.
+ </p>
+
+ <p><a class="target" name="basic"><h2>Basic HTTP authentication</h2></a></p>
+ <p>
+ If you fetch a page protected by basic authentication then
+ rather than receiving content, you will instead get a 401
+ header.
+ We can illustrate this with this test...
+<pre>
+class AuthenticationTest extends WebTestCase {<strong>
+ function test401Header() {
+ $this-&gt;get('http://www.lastcraft.com/protected/');
+ $this-&gt;showHeaders();
+ }</strong>
+}
+</pre>
+ This allows us to see the challenge header...
+ <div class="demo">
+ <h1>File test</h1>
+<pre style="background-color: lightgray; color: black">
+HTTP/1.1 401 Authorization Required
+Date: Sat, 18 Sep 2004 19:25:18 GMT
+Server: Apache/1.3.29 (Unix) PHP/4.3.4
+WWW-Authenticate: Basic realm="SimpleTest basic authentication"
+Connection: close
+Content-Type: text/html; charset=iso-8859-1
+</pre>
+ <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
+ <strong>0</strong> passes, <strong>0</strong> fails and <strong>0</strong> exceptions.</div>
+ </div>
+ We are trying to get away from visual inspection though, and so SimpleTest
+ allows to make automated assertions against the challenge.
+ Here is a thorough test of our header...
+<pre>
+class AuthenticationTest extends WebTestCase {
+ function test401Header() {
+ $this-&gt;get('http://www.lastcraft.com/protected/');<strong>
+ $this-&gt;assertAuthentication('Basic');
+ $this-&gt;assertResponse(401);
+ $this-&gt;assertRealm('SimpleTest basic authentication');</strong>
+ }
+}
+</pre>
+ Any one of these tests would normally do on it's own depending
+ on the amount of detail you want to see.
+ </p>
+ <p>
+ One theme that runs through SimpleTest is the ability to use
+ <span class="new_code">SimpleExpectation</span> objects wherever a simple
+ match is not enough.
+ If you want only an approximate match to the realm for
+ example, you can do this...
+<pre>
+class AuthenticationTest extends WebTestCase {
+ function test401Header() {
+ $this-&gt;get('http://www.lastcraft.com/protected/');
+ $this-&gt;assertRealm(<strong>new PatternExpectation('/simpletest/i')</strong>);
+ }
+}
+</pre>
+ Most of the time we are not interested in testing the
+ authentication itself, but want to get past it to test
+ the pages underneath.
+ As soon as the challenge has been issued we can reply with
+ an authentication response...
+<pre>
+class AuthenticationTest extends WebTestCase {
+ function testCanAuthenticate() {
+ $this-&gt;get('http://www.lastcraft.com/protected/');<strong>
+ $this-&gt;authenticate('Me', 'Secret');</strong>
+ $this-&gt;assertTitle(...);
+ }
+}
+</pre>
+ The username and password will now be sent with every
+ subsequent request to that directory and subdirectories.
+ You will have to authenticate again if you step outside
+ the authenticated directory, but SimpleTest is smart enough
+ to merge subdirectories into a common realm.
+ </p>
+ <p>
+ You can shortcut this step further by encoding the log in
+ details straight into the URL...
+<pre>
+class AuthenticationTest extends WebTestCase {
+ function testCanReadAuthenticatedPages() {
+ $this-&gt;get('http://<strong>Me:Secret@</strong>www.lastcraft.com/protected/');
+ $this-&gt;assertTitle(...);
+ }
+}
+</pre>
+ If your username or password has special characters, then you
+ will have to URL encode them or the request will not be parsed
+ correctly.
+ Also this header will not be sent on subsequent requests if
+ you request a page with a fully qualified URL.
+ If you navigate with relative URLs though, the authentication
+ information will be preserved.
+ </p>
+ <p>
+ Only basic authentication is currently supported and this is
+ only really secure in tandem with HTTPS connections.
+ This is usually enough to protect test server from prying eyes,
+ however.
+ Digest authentication and NTLM authentication may be added
+ in the future.
+ </p>
+
+ <p><a class="target" name="cookies"><h2>Cookies</h2></a></p>
+ <p>
+ Basic authentication doesn't give enough control over the
+ user interface for web developers.
+ More likely this functionality will be coded directly into
+ the web architecture using cookies and complicated timeouts.
+ </p>
+ <p>
+ Starting with a simple log-in form...
+<pre>
+&lt;form&gt;
+ Username:
+ &lt;input type="text" name="u" value="" /&gt;&lt;br /&gt;
+ Password:
+ &lt;input type="password" name="p" value="" /&gt;&lt;br /&gt;
+ &lt;input type="submit" value="Log in" /&gt;
+&lt;/form&gt;
+</pre>
+ Which looks like...
+ </p>
+ <p>
+ <form class="demo">
+ Username:
+ <input type="text" name="u" value=""><br>
+ Password:
+ <input type="password" name="p" value=""><br>
+ <input type="submit" value="Log in">
+ </form>
+ </p>
+ <p>
+ Let's suppose that in fetching this page a cookie has been
+ set with a session ID.
+ We are not going to fill the form in yet, just test that
+ we are tracking the user.
+ Here is the test...
+<pre>
+class LogInTest extends WebTestCase {
+ function testSessionCookieSetBeforeForm() {
+ $this-&gt;get('http://www.my-site.com/login.php');<strong>
+ $this-&gt;assertCookie('SID');</strong>
+ }
+}
+</pre>
+ All we are doing is confirming that the cookie is set.
+ As the value is likely to be rather cryptic it's not
+ really worth testing this with...
+<pre>
+class LogInTest extends WebTestCase {
+ function testSessionCookieIsCorrectPattern() {
+ $this-&gt;get('http://www.my-site.com/login.php');
+ $this-&gt;assertCookie('SID', <strong>new PatternExpectation('/[a-f0-9]{32}/i')</strong>);
+ }
+}
+</pre>
+ The rest of the test would be the same as any other form,
+ but we might want to confirm that we still have the same
+ cookie after log-in as before we entered.
+ We wouldn't want to lose track of this after all.
+ Here is a possible test for this...
+<pre>
+class LogInTest extends WebTestCase {
+ ...
+ function testSessionCookieSameAfterLogIn() {
+ $this-&gt;get('http://www.my-site.com/login.php');<strong>
+ $session = $this-&gt;getCookie('SID');
+ $this-&gt;setField('u', 'Me');
+ $this-&gt;setField('p', 'Secret');
+ $this-&gt;click('Log in');
+ $this-&gt;assertText('Welcome Me');
+ $this-&gt;assertCookie('SID', $session);</strong>
+ }
+}
+</pre>
+ This confirms that the session identifier is maintained
+ afer log-in.
+ </p>
+ <p>
+ We could even attempt to spoof our own system by setting
+ arbitrary cookies to gain access...
+<pre>
+class LogInTest extends WebTestCase {
+ ...
+ function testSessionCookieSameAfterLogIn() {
+ $this-&gt;get('http://www.my-site.com/login.php');<strong>
+ $this-&gt;setCookie('SID', 'Some other session');
+ $this-&gt;get('http://www.my-site.com/restricted.php');</strong>
+ $this-&gt;assertText('Access denied');
+ }
+}
+</pre>
+ Is your site protected from this attack?
+ </p>
+
+ <p><a class="target" name="session"><h2>Browser sessions</h2></a></p>
+ <p>
+ If you are testing an authentication system a critical piece
+ of behaviour is what happens when a user logs back in.
+ We would like to simulate closing and reopening a browser...
+<pre>
+class LogInTest extends WebTestCase {
+ ...
+ function testLoseAuthenticationAfterBrowserClose() {
+ $this-&gt;get('http://www.my-site.com/login.php');
+ $this-&gt;setField('u', 'Me');
+ $this-&gt;setField('p', 'Secret');
+ $this-&gt;click('Log in');
+ $this-&gt;assertText('Welcome Me');<strong>
+
+ $this-&gt;restart();
+ $this-&gt;get('http://www.my-site.com/restricted.php');
+ $this-&gt;assertText('Access denied');</strong>
+ }
+}
+</pre>
+ The <span class="new_code">WebTestCase::restart()</span> method will
+ preserve cookies that have unexpired timeouts, but throw away
+ those that are temporary or expired.
+ You can optionally specify the time and date that the restart
+ happened.
+ </p>
+ <p>
+ Expiring cookies can be a problem.
+ After all, if you have a cookie that expires after an hour,
+ you don't want to stall the test for an hour while the
+ cookie passes it's timeout.
+ </p>
+ <p>
+ To push the cookies over the hour limit you can age them
+ before you restart the session...
+<pre>
+class LogInTest extends WebTestCase {
+ ...
+ function testLoseAuthenticationAfterOneHour() {
+ $this-&gt;get('http://www.my-site.com/login.php');
+ $this-&gt;setField('u', 'Me');
+ $this-&gt;setField('p', 'Secret');
+ $this-&gt;click('Log in');
+ $this-&gt;assertText('Welcome Me');
+ <strong>
+ $this-&gt;ageCookies(3600);</strong>
+ $this-&gt;restart();
+ $this-&gt;get('http://www.my-site.com/restricted.php');
+ $this-&gt;assertText('Access denied');
+ }
+}
+</pre>
+ After the restart it will appear that cookies are an
+ hour older and any that pass their expiry will have
+ disappeared.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
+ gives full detail on the classes and assertions available.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <span class="chosen">Authentication</span>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/browser_documentation.html b/vendors/simpletest/docs/en/browser_documentation.html
new file mode 100644
index 000000000..522f3a598
--- /dev/null
+++ b/vendors/simpletest/docs/en/browser_documentation.html
@@ -0,0 +1,447 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest documentation for the scriptable web browser component</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <span class="chosen">Scriptable browser</span>
+</div></div>
+<h1>PHP Scriptable Web Browser</h1>
+ This page...
+ <ul>
+<li>
+ Using the bundled <a href="#scripting">web browser in scripts</a>
+ </li>
+<li>
+ <a href="#debug">Debugging</a> failed pages
+ </li>
+<li>
+ Complex <a href="#unit">tests with multiple web browsers</a>
+ </li>
+</ul>
+<div class="content">
+
+ <p>
+ SimpleTest's web browser component can be used not just
+ outside of the <span class="new_code">WebTestCase</span> class, but also
+ independently of the SimpleTest framework itself.
+ </p>
+
+ <p><a class="target" name="scripting"><h2>The Scriptable Browser</h2></a></p>
+ <p>
+ You can use the web browser in PHP scripts to confirm
+ services are up and running, or to extract information
+ from them at a regular basis.
+ For example, here is a small script to extract the current number of
+ open PHP 5 bugs from the <a href="http://www.php.net/">PHP web site</a>...
+<pre>
+<strong>&lt;?php
+require_once('simpletest/browser.php');
+
+$browser = &amp;new SimpleBrowser();
+$browser-&gt;get('http://php.net/');
+$browser-&gt;click('reporting bugs');
+$browser-&gt;click('statistics');
+$page = $browser-&gt;click('PHP 5 bugs only');
+preg_match('/status=Open.*?by=Any.*?(\d+)&lt;\/a&gt;/', $page, $matches);
+print $matches[1];
+?&gt;</strong>
+</pre>
+ There are simpler methods to do this particular example in PHP
+ of course.
+ For example you can just use the PHP <span class="new_code">file()</span>
+ command against what here is a pretty fixed page.
+ However, using the web browser for scripts allows authentication,
+ correct handling of cookies, automatic loading of frames, redirects,
+ form submission and the ability to examine the page headers.
+ Such methods are fragile against a site that is constantly
+ evolving and you would want a more direct way of accessing
+ data in a permanent set up, but for simple tasks this can provide
+ a very rapid solution.
+ </p>
+ <p>
+ All of the navigation methods used in the
+ <a href="web_tester_documentation.html">WebTestCase</a>
+ are present in the <span class="new_code">SimpleBrowser</span> class, but
+ the assertions are replaced with simpler accessors.
+ Here is a full list of the page navigation methods...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">addHeader($header)</span></td>
+<td>Adds a header to every fetch</td>
+</tr>
+ <tr>
+<td><span class="new_code">useProxy($proxy, $username, $password)</span></td>
+<td>Use this proxy from now on</td>
+</tr>
+ <tr>
+<td><span class="new_code">head($url, $parameters)</span></td>
+<td>Perform a HEAD request</td>
+</tr>
+ <tr>
+<td><span class="new_code">get($url, $parameters)</span></td>
+<td>Fetch a page with GET</td>
+</tr>
+ <tr>
+<td><span class="new_code">post($url, $parameters)</span></td>
+<td>Fetch a page with POST</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickLink($label)</span></td>
+<td>Follows a link by label</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickLinkById($id)</span></td>
+<td>Follows a link by attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">getUrl()</span></td>
+<td>Current URL of page or frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">getTitle()</span></td>
+<td>Page title</td>
+</tr>
+ <tr>
+<td><span class="new_code">getContent()</span></td>
+<td>Raw page or frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">getContentAsText()</span></td>
+<td>HTML removed except for alt text</td>
+</tr>
+ <tr>
+<td><span class="new_code">retry()</span></td>
+<td>Repeat the last request</td>
+</tr>
+ <tr>
+<td><span class="new_code">back()</span></td>
+<td>Use the browser back button</td>
+</tr>
+ <tr>
+<td><span class="new_code">forward()</span></td>
+<td>Use the browser forward button</td>
+</tr>
+ <tr>
+<td><span class="new_code">authenticate($username, $password)</span></td>
+<td>Retry page or frame after a 401 response</td>
+</tr>
+ <tr>
+<td><span class="new_code">restart($date)</span></td>
+<td>Restarts the browser for a new session</td>
+</tr>
+ <tr>
+<td><span class="new_code">ageCookies($interval)</span></td>
+<td>Ages the cookies by the specified time</td>
+</tr>
+ <tr>
+<td><span class="new_code">setCookie($name, $value)</span></td>
+<td>Sets an additional cookie</td>
+</tr>
+ <tr>
+<td><span class="new_code">getCookieValue($host, $path, $name)</span></td>
+<td>Reads the most specific cookie</td>
+</tr>
+ <tr>
+<td><span class="new_code">getCurrentCookieValue($name)</span></td>
+<td>Reads cookie for the current context</td>
+</tr>
+ </tbody></table>
+ The methods <span class="new_code">SimpleBrowser::useProxy()</span> and
+ <span class="new_code">SimpleBrowser::addHeader()</span> are special.
+ Once called they continue to apply to all subsequent fetches.
+ </p>
+ <p>
+ Navigating forms is similar to the
+ <a href="form_testing_documentation.html">WebTestCase form navigation</a>...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">setField($name, $value)</span></td>
+<td>Sets all form fields with that name</td>
+</tr>
+ <tr>
+<td><span class="new_code">setFieldById($id, $value)</span></td>
+<td>Sets all form fields with that id</td>
+</tr>
+ <tr>
+<td><span class="new_code">getField($name)</span></td>
+<td>Accessor for a form element value</td>
+</tr>
+ <tr>
+<td><span class="new_code">getFieldById($id)</span></td>
+<td>Accessor for a form element value</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickSubmit($label)</span></td>
+<td>Submits form by button label</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickSubmitByName($name)</span></td>
+<td>Submits form by button attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickSubmitById($id)</span></td>
+<td>Submits form by button attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickImage($label, $x, $y)</span></td>
+<td>Clicks an input tag of type image by title or alt text</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickImageByName($name, $x, $y)</span></td>
+<td>Clicks an input tag of type image by name</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickImageById($id, $x, $y)</span></td>
+<td>Clicks an input tag of type image by ID attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">submitFormById($id)</span></td>
+<td>Submits by the form tag attribute</td>
+</tr>
+ </tbody></table>
+ At the moment there aren't any methods to list available forms
+ and fields.
+ This will probably be added to later versions of SimpleTest.
+ </p>
+ <p>
+ Within a page, individual frames can be selected.
+ If no selection is made then all the frames are merged together
+ in one large conceptual page.
+ The content of the current page will be a concatenation of all of the
+ frames in the order that they were specified in the "frameset"
+ tags.
+ <table><tbody>
+ <tr>
+<td><span class="new_code">getFrames()</span></td>
+<td>A dump of the current frame structure</td>
+</tr>
+ <tr>
+<td><span class="new_code">getFrameFocus()</span></td>
+<td>Current frame label or index</td>
+</tr>
+ <tr>
+<td><span class="new_code">setFrameFocusByIndex($choice)</span></td>
+<td>Select a frame numbered from 1</td>
+</tr>
+ <tr>
+<td><span class="new_code">setFrameFocus($name)</span></td>
+<td>Select frame by label</td>
+</tr>
+ <tr>
+<td><span class="new_code">clearFrameFocus()</span></td>
+<td>Treat all the frames as a single page</td>
+</tr>
+ </tbody></table>
+ When focused on a single frame, the content will come from
+ that frame only.
+ This includes links to click and forms to submit.
+ </p>
+
+ <p><a class="target" name="debug"><h2>What went wrong?</h2></a></p>
+ <p>
+ All of this functionality is great when we actually manage to fetch pages,
+ but that doesn't always happen.
+ To help figure out what went wrong, the browser has some methods to
+ aid in debugging...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">setConnectionTimeout($timeout)</span></td>
+<td>Close the socket on overrun</td>
+</tr>
+ <tr>
+<td><span class="new_code">getRequest()</span></td>
+<td>Raw request header of page or frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">getHeaders()</span></td>
+<td>Raw response header of page or frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">getTransportError()</span></td>
+<td>Any socket level errors in the last fetch</td>
+</tr>
+ <tr>
+<td><span class="new_code">getResponseCode()</span></td>
+<td>HTTP response of page or frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">getMimeType()</span></td>
+<td>Mime type of page or frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">getAuthentication()</span></td>
+<td>Authentication type in 401 challenge header</td>
+</tr>
+ <tr>
+<td><span class="new_code">getRealm()</span></td>
+<td>Authentication realm in 401 challenge header</td>
+</tr>
+ <tr>
+<td><span class="new_code">setMaximumRedirects($max)</span></td>
+<td>Number of redirects before page is loaded anyway</td>
+</tr>
+ <tr>
+<td><span class="new_code">setMaximumNestedFrames($max)</span></td>
+<td>Protection against recursive framesets</td>
+</tr>
+ <tr>
+<td><span class="new_code">ignoreFrames()</span></td>
+<td>Disables frames support</td>
+</tr>
+ <tr>
+<td><span class="new_code">useFrames()</span></td>
+<td>Enables frames support</td>
+</tr>
+ <tr>
+<td><span class="new_code">ignoreCookies()</span></td>
+<td>Disables sending and receiving of cookies</td>
+</tr>
+ <tr>
+<td><span class="new_code">useCookies()</span></td>
+<td>Enables cookie support</td>
+</tr>
+ </tbody></table>
+ The methods <span class="new_code">SimpleBrowser::setConnectionTimeout()</span>
+ <span class="new_code">SimpleBrowser::setMaximumRedirects()</span>,
+ <span class="new_code">SimpleBrowser::setMaximumNestedFrames()</span>,
+ <span class="new_code">SimpleBrowser::ignoreFrames()</span>,
+ <span class="new_code">SimpleBrowser::useFrames()</span>,
+ <span class="new_code">SimpleBrowser::ignoreCookies()</span> and
+ <span class="new_code">SimpleBrowser::useCokies()</span> continue to apply
+ to every subsequent request.
+ The other methods are frames aware.
+ This means that if you have an individual frame that is not
+ loading, navigate to it using <span class="new_code">SimpleBrowser::setFrameFocus()</span>
+ and you can then use <span class="new_code">SimpleBrowser::getRequest()</span>, etc to
+ see what happened.
+ </p>
+
+ <p><a class="target" name="unit"><h2>Complex unit tests with multiple browsers</h2></a></p>
+ <p>
+ Anything that could be done in a
+ <a href="web_tester_documentation.html">WebTestCase</a> can
+ now be done in a <a href="unit_tester_documentation.html">UnitTestCase</a>.
+ This means that we can freely mix domain object testing with the
+ web interface...
+<pre>
+<strong>class TestOfRegistration extends UnitTestCase {
+ function testNewUserAddedToAuthenticator() {</strong>
+ $browser = &amp;new SimpleBrowser();
+ $browser-&gt;get('http://my-site.com/register.php');
+ $browser-&gt;setField('email', 'me@here');
+ $browser-&gt;setField('password', 'Secret');
+ $browser-&gt;click('Register');
+ <strong>
+ $authenticator = &amp;new Authenticator();
+ $member = &amp;$authenticator-&gt;findByEmail('me@here');
+ $this-&gt;assertEqual($member-&gt;getPassword(), 'Secret');
+ }
+}</strong>
+</pre>
+ While this may be a useful temporary expediency, I am not a fan
+ of this type of testing.
+ The testing has cut across application layers, make it twice as
+ likely it will need refactoring when the code changes.
+ </p>
+ <p>
+ A more useful case of where using the browser directly can be helpful
+ is where the <span class="new_code">WebTestCase</span> cannot cope.
+ An example is where two browsers are needed at the same time.
+ </p>
+ <p>
+ For example, say we want to disallow multiple simultaneous
+ usage of a site with the same username.
+ This test case will do the job...
+<pre>
+class TestOfSecurity extends UnitTestCase {
+ function testNoMultipleLoginsFromSameUser() {<strong>
+ $first = &amp;new SimpleBrowser();
+ $first-&gt;get('http://my-site.com/login.php');
+ $first-&gt;setField('name', 'Me');
+ $first-&gt;setField('password', 'Secret');
+ $first-&gt;click('Enter');
+ $this-&gt;assertEqual($first-&gt;getTitle(), 'Welcome');
+
+ $second = &amp;new SimpleBrowser();
+ $second-&gt;get('http://my-site.com/login.php');
+ $second-&gt;setField('name', 'Me');
+ $second-&gt;setField('password', 'Secret');
+ $second-&gt;click('Enter');
+ $this-&gt;assertEqual($second-&gt;getTitle(), 'Access Denied');</strong>
+ }
+}
+</pre>
+ You can also use the <span class="new_code">SimpleBrowser</span> class
+ directly when you want to write test cases using a different
+ test tool than SimpleTest.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
+ gives full detail on the classes and assertions available.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <span class="chosen">Scriptable browser</span>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/docs.css b/vendors/simpletest/docs/en/docs.css
new file mode 100644
index 000000000..18368a04f
--- /dev/null
+++ b/vendors/simpletest/docs/en/docs.css
@@ -0,0 +1,121 @@
+body {
+ padding-left: 3%;
+ padding-right: 3%;
+}
+h1, h2, h3 {
+ font-family: sans-serif;
+}
+h1 {
+ text-align: center;
+}
+pre {
+ font-family: "courier new", courier, typewriter, monospace;
+ font-size: 90%;
+ border: 1px solid;
+ border-color: #999966;
+ background-color: #ffffcc;
+ padding: 5px;
+ margin-left: 20px;
+ margin-right: 40px;
+}
+.code, .new_code, pre.new_code {
+ font-family: "courier new", courier, typewriter, monospace;
+ font-weight: bold;
+}
+div.copyright {
+ font-size: 80%;
+ color: gray;
+}
+div.copyright a {
+ margin-top: 1em;
+ color: gray;
+}
+ul.api {
+ border: 2px outset;
+ border-color: gray;
+ background-color: white;
+ margin: 5px;
+ margin-left: 5%;
+ margin-right: 5%;
+}
+ul.api li {
+ margin-top: 0.2em;
+ margin-bottom: 0.2em;
+ list-style: none;
+ text-indent: -3em;
+ padding-left: 1em;
+}
+div.demo {
+ border: 4px ridge;
+ border-color: gray;
+ padding: 10px;
+ margin: 5px;
+ margin-left: 20px;
+ margin-right: 40px;
+ background-color: white;
+}
+div.demo span.fail {
+ color: red;
+}
+div.demo span.pass {
+ color: green;
+}
+div.demo h1 {
+ font-size: 12pt;
+ text-align: left;
+ font-weight: bold;
+}
+div.menu {
+ text-align: center;
+}
+table {
+ border: 2px outset;
+ border-color: gray;
+ background-color: white;
+ margin: 5px;
+ margin-left: 5%;
+ margin-right: 5%;
+}
+td {
+ font-size: 90%;
+}
+.shell {
+ color: white;
+}
+pre.shell {
+ border: 4px ridge;
+ border-color: gray;
+ padding: 10px;
+ margin: 5px;
+ margin-left: 20px;
+ margin-right: 40px;
+ background-color: #000100;
+ color: #99ff99;
+ font-size: 90%;
+}
+pre.file {
+ color: black;
+ border: 1px solid;
+ border-color: black;
+ padding: 10px;
+ margin: 5px;
+ margin-left: 20px;
+ margin-right: 40px;
+ background-color: white;
+ font-size: 90%;
+}
+form.demo {
+ background-color: lightgray;
+ border: 4px outset;
+ border-color: lightgray;
+ padding: 10px;
+ margin-right: 40%;
+}
+dl, dd {
+ margin: 10px;
+ margin-left: 30px;
+}
+em {
+ font-weight: bold;
+ font-family: "courier new", courier, typewriter, monospace;
+}
diff --git a/vendors/simpletest/docs/en/expectation_documentation.html b/vendors/simpletest/docs/en/expectation_documentation.html
new file mode 100644
index 000000000..c3c959c4c
--- /dev/null
+++ b/vendors/simpletest/docs/en/expectation_documentation.html
@@ -0,0 +1,422 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>
+ Extending the SimpleTest unit tester with additional expectation classes
+ </title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <span class="chosen">Expectations</span>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Expectation documentation</h1>
+ This page...
+ <ul>
+<li>
+ Using expectations for
+ <a href="#mock">more precise testing with mock objects</a>
+ </li>
+<li>
+ <a href="#behaviour">Changing mock object behaviour</a> with expectations
+ </li>
+<li>
+ <a href="#extending">Extending the expectations</a>
+ </li>
+<li>
+ Underneath SimpleTest <a href="#unit">uses expectation classes</a>
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="mock"><h2>More control over mock objects</h2></a></p>
+ <p>
+ The default behaviour of the
+ <a href="mock_objects_documentation.html">mock objects</a>
+ in
+ <a href="http://sourceforge.net/projects/simpletest/">SimpleTest</a>
+ is either an identical match on the argument or to allow any argument at all.
+ For almost all tests this is sufficient.
+ Sometimes, though, you want to weaken a test case.
+ </p>
+ <p>
+ One place where a test can be too tightly coupled is with
+ text matching.
+ Suppose we have a component that outputs a helpful error
+ message when something goes wrong.
+ You want to test that the correct error was sent, but the actual
+ text may be rather long.
+ If you test for the text exactly, then every time the exact wording
+ of the message changes, you will have to go back and edit the test suite.
+ </p>
+ <p>
+ For example, suppose we have a news service that has failed
+ to connect to its remote source.
+<pre>
+<strong>class NewsService {
+ ...
+ function publish(&amp;$writer) {
+ if (! $this-&gt;isConnected()) {
+ $writer-&gt;write('Cannot connect to news service "' .
+ $this-&gt;_name . '" at this time. ' .
+ 'Please try again later.');
+ }
+ ...
+ }
+}</strong>
+</pre>
+ Here it is sending its content to a
+ <span class="new_code">Writer</span> class.
+ We could test this behaviour with a
+ <span class="new_code">MockWriter</span> like so...
+<pre>
+class TestOfNewsService extends UnitTestCase {
+ ...
+ function testConnectionFailure() {<strong>
+ $writer = &amp;new MockWriter();
+ $writer-&gt;expectOnce('write', array(
+ 'Cannot connect to news service ' .
+ '"BBC News" at this time. ' .
+ 'Please try again later.'));
+
+ $service = &amp;new NewsService('BBC News');
+ $service-&gt;publish($writer);</strong>
+ }
+}
+</pre>
+ This is a good example of a brittle test.
+ If we decide to add additional instructions, such as
+ suggesting an alternative news source, we will break
+ our tests even though no underlying functionality
+ has been altered.
+ </p>
+ <p>
+ To get around this, we would like to do a regular expression
+ test rather than an exact match.
+ We can actually do this with...
+<pre>
+class TestOfNewsService extends UnitTestCase {
+ ...
+ function testConnectionFailure() {
+ $writer = &amp;new MockWriter();<strong>
+ $writer-&gt;expectOnce(
+ 'write',
+ array(new PatternExpectation('/cannot connect/i')));</strong>
+
+ $service = &amp;new NewsService('BBC News');
+ $service-&gt;publish($writer);
+ }
+}
+</pre>
+ Instead of passing in the expected parameter to the
+ <span class="new_code">MockWriter</span> we pass an
+ expectation class called
+ <span class="new_code">WantedPatternExpectation</span>.
+ The mock object is smart enough to recognise this as special
+ and to treat it differently.
+ Rather than simply comparing the incoming argument to this
+ object, it uses the expectation object itself to
+ perform the test.
+ </p>
+ <p>
+ The <span class="new_code">WantedPatternExpectation</span> takes
+ the regular expression to match in its constructor.
+ Whenever a comparison is made by the <span class="new_code">MockWriter</span>
+ against this expectation class, it will do a
+ <span class="new_code">preg_match()</span> with this pattern.
+ With our test case above, as long as "cannot connect"
+ appears in the text of the string, the mock will issue a pass
+ to the unit tester.
+ The rest of the text does not matter.
+ </p>
+ <p>
+ The possible expectation classes are...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">AnythingExpectation</span></td>
+<td>Will always match</td>
+</tr>
+ <tr>
+<td><span class="new_code">EqualExpectation</span></td>
+<td>An equality, rather than the stronger identity comparison</td>
+</tr>
+ <tr>
+<td><span class="new_code">NotEqualExpectation</span></td>
+<td>An inequality comparison</td>
+</tr>
+ <tr>
+<td><span class="new_code">IndenticalExpectation</span></td>
+<td>The default mock object check which must match exactly</td>
+</tr>
+ <tr>
+<td><span class="new_code">NotIndenticalExpectation</span></td>
+<td>Inverts the mock object logic</td>
+</tr>
+ <tr>
+<td><span class="new_code">WithinMarginExpectation</span></td>
+<td>Compares a value to within a margin</td>
+</tr>
+ <tr>
+<td><span class="new_code">OutsideMarginExpectation</span></td>
+<td>Checks that a value is out side the margin</td>
+</tr>
+ <tr>
+<td><span class="new_code">PatternExpectation</span></td>
+<td>Uses a Perl Regex to match a string</td>
+</tr>
+ <tr>
+<td><span class="new_code">NoPatternExpectation</span></td>
+<td>Passes only if failing a Perl Regex</td>
+</tr>
+ <tr>
+<td><span class="new_code">IsAExpectation</span></td>
+<td>Checks the type or class name only</td>
+</tr>
+ <tr>
+<td><span class="new_code">NotAExpectation</span></td>
+<td>Opposite of the <span class="new_code">IsAExpectation</span>
+</td>
+</tr>
+ <tr>
+<td><span class="new_code">MethodExistsExpectation</span></td>
+<td>Checks a method is available on an object</td>
+</tr>
+ </tbody></table>
+ Most take the expected value in the constructor.
+ The exceptions are the pattern matchers, which take a regular expression,
+ and the <span class="new_code">IsAExpectation</span> and <span class="new_code">NotAExpectation</span> which takes a type
+ or class name as a string.
+ </p>
+ <p>
+ Some examples...
+ </p>
+ <p>
+<pre>
+$mock-&gt;expectOnce('method', array(new IdenticalExpectation(14)));
+</pre>
+ This is the same as <span class="new_code">$mock-&gt;expectOnce('method', array(14))</span>.
+<pre>
+$mock-&gt;expectOnce('method', array(new EqualExpectation(14)));
+</pre>
+ This is different from the previous version in that the string
+ <span class="new_code">"14"</span> as a parameter will also pass.
+ Sometimes the additional type checks of SimpleTest are too restrictive.
+<pre>
+$mock-&gt;expectOnce('method', array(new AnythingExpectation(14)));
+</pre>
+ This is the same as <span class="new_code">$mock-&gt;expectOnce('method', array('*'))</span>.
+<pre>
+$mock-&gt;expectOnce('method', array(new IdenticalExpectation('*')));
+</pre>
+ This is handy if you want to assert a literal <span class="new_code">"*"</span>.
+<pre>
+new NotIdenticalExpectation(14)
+</pre>
+ This matches on anything other than integer 14.
+ Even the string <span class="new_code">"14"</span> would pass.
+<pre>
+new WithinMarginExpectation(14.0, 0.001)
+</pre>
+ This will accept any value from 13.999 to 14.001 inclusive.
+ </p>
+
+ <p><a class="target" name="behaviour"><h2>Using expectations to control stubs</h2></a></p>
+ <p>
+ The expectation classes can be used not just for sending assertions
+ from mock objects, but also for selecting behaviour for the
+ <a href="mock_objects_documentation.html">mock objects</a>.
+ Anywhere a list of arguments is given, a list of expectation objects
+ can be inserted instead.
+ </p>
+ <p>
+ Suppose we want a mock authorisation server to simulate a successful login,
+ but only if it receives a valid session object.
+ We can do this as follows...
+<pre>
+Mock::generate('Authorisation');
+<strong>
+$authorisation = new MockAuthorisation();
+$authorisation-&gt;setReturnValue(
+ 'isAllowed',
+ true,
+ array(new IsAExpectation('Session', 'Must be a session')));
+$authorisation-&gt;setReturnValue('isAllowed', false);</strong>
+</pre>
+ We have set the default mock behaviour to return false when
+ <span class="new_code">isAllowed</span> is called.
+ When we call the method with a single parameter that
+ is a <span class="new_code">Session</span> object, it will return true.
+ We have also added a second parameter as a message.
+ This will be displayed as part of the mock object
+ failure message if this expectation is the cause of
+ a failure.
+ </p>
+ <p>
+ This kind of sophistication is rarely useful, but is included for
+ completeness.
+ </p>
+
+ <p><a class="target" name="extending"><h2>Creating your own expectations</h2></a></p>
+ <p>
+ The expectation classes have a very simple structure.
+ So simple that it is easy to create your own versions for
+ commonly used test logic.
+ </p>
+ <p>
+ As an example here is the creation of a class to test for
+ valid IP addresses.
+ In order to work correctly with the stubs and mocks the new
+ expectation class should extend
+ <span class="new_code">SimpleExpectation</span>...
+<pre>
+<strong>class ValidIp extends SimpleExpectation {
+
+ function test($ip) {
+ return (ip2long($ip) != -1);
+ }
+
+ function testMessage($ip) {
+ return "Address [$ip] should be a valid IP address";
+ }
+}</strong>
+</pre>
+ There are only two methods to implement.
+ The <span class="new_code">test()</span> method should
+ evaluate to true if the expectation is to pass, and
+ false otherwise.
+ The <span class="new_code">testMessage()</span> method
+ should simply return some helpful text explaining the test
+ that was carried out.
+ </p>
+ <p>
+ This class can now be used in place of the earlier expectation
+ classes.
+ </p>
+
+ <p><a class="target" name="unit"><h2>Under the bonnet of the unit tester</h2></a></p>
+ <p>
+ The <a href="http://sourceforge.net/projects/simpletest/">SimpleTest unit testing framework</a>
+ also uses the expectation classes internally for the
+ <a href="unit_test_documentation.html">UnitTestCase class</a>.
+ We can also take advantage of these mechanisms to reuse our
+ homebrew expectation classes within the test suites directly.
+ </p>
+ <p>
+ The most crude way of doing this is to use the
+ <span class="new_code">SimpleTest::assert()</span> method to
+ test against it directly...
+<pre>
+<strong>class TestOfNetworking extends UnitTestCase {
+ ...
+ function testGetValidIp() {
+ $server = &amp;new Server();
+ $this-&gt;assert(
+ new ValidIp(),
+ $server-&gt;getIp(),
+ 'Server IP address-&gt;%s');
+ }
+}</strong>
+</pre>
+ This is a little untidy compared with our usual
+ <span class="new_code">assert...()</span> syntax.
+ </p>
+ <p>
+ For such a simple case we would normally create a
+ separate assertion method on our test case rather
+ than bother using the expectation class.
+ If we pretend that our expectation is a little more
+ complicated for a moment, so that we want to reuse it,
+ we get...
+<pre>
+class TestOfNetworking extends UnitTestCase {
+ ...<strong>
+ function assertValidIp($ip, $message = '%s') {
+ $this-&gt;assert(new ValidIp(), $ip, $message);
+ }</strong>
+
+ function testGetValidIp() {
+ $server = &amp;new Server();<strong>
+ $this-&gt;assertValidIp(
+ $server-&gt;getIp(),
+ 'Server IP address-&gt;%s');</strong>
+ }
+}
+</pre>
+ It is unlikely we would ever need this degree of control
+ over the testing machinery.
+ It is rare to need the expectations for more than pattern
+ matching.
+ Also, complex expectation classes could make the tests
+ harder to read and debug.
+ These mechanisms are really of most use to authors of systems
+ that will extend the test framework to create their own tool set.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ The expectations mimic the constraints in <a href="http://www.jmock.org/">JMock</a>.
+ </li>
+<li>
+ <a href="http://simpletest.org/api/">Full API for SimpleTest</a>
+ from the PHPDoc.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <span class="chosen">Expectations</span>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/form_testing_documentation.html b/vendors/simpletest/docs/en/form_testing_documentation.html
new file mode 100644
index 000000000..fe0fcccf0
--- /dev/null
+++ b/vendors/simpletest/docs/en/form_testing_documentation.html
@@ -0,0 +1,342 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Simple Test documentation for testing HTML forms</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <span class="chosen">Testing forms</span>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Form testing documentation</h1>
+ This page...
+ <ul>
+<li>
+ Changing form values and successfully
+ <a href="#submit">Submitting a simple form</a>
+ </li>
+<li>
+ Handling <a href="#multiple">widgets with multiple values</a>
+ by setting lists.
+ </li>
+<li>
+ Bypassing javascript to <a href="#hidden-field">set a hidden field</a>.
+ </li>
+<li>
+ <a href="#raw">Raw posting</a> when you don't have a button
+ to click.
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="submit"><h2>Submitting a simple form</h2></a></p>
+ <p>
+ When a page is fetched by the <span class="new_code">WebTestCase</span>
+ using <span class="new_code">get()</span> or
+ <span class="new_code">post()</span> the page content is
+ automatically parsed.
+ This results in any form controls that are inside &lt;form&gt; tags
+ being available from within the test case.
+ For example, if we have this snippet of HTML...
+<pre>
+&lt;form&gt;
+ &lt;input type="text" name="a" value="A default" /&gt;
+ &lt;input type="submit" value="Go" /&gt;
+&lt;/form&gt;
+</pre>
+ Which looks like this...
+ </p>
+ <p>
+ <form class="demo">
+ <input type="text" name="a" value="A default">
+ <input type="submit" value="Go">
+ </form>
+ </p>
+ <p>
+ We can navigate to this code, via the
+ <a href="http://www.lastcraft.com/form_testing_documentation.php">LastCraft</a>
+ site, with the following test...
+<pre>
+class SimpleFormTests extends WebTestCase {
+ <strong>
+ function testDefaultValue() {
+ $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
+ $this-&gt;assertField('a', 'A default');
+ }</strong>
+}
+</pre>
+ Immediately after loading the page all of the HTML controls are set at
+ their default values just as they would appear in the web browser.
+ The assertion tests that a HTML widget exists in the page with the
+ name "a" and that it is currently set to the value
+ "A default".
+ As usual, we could use a pattern expectation instead if a fixed
+ string.
+ </p>
+ <p>
+ We could submit the form straight away, but first we'll change
+ the value of the text field and only then submit it...
+<pre>
+class SimpleFormTests extends WebTestCase {
+
+ function testDefaultValue() {
+ $this-&gt;get('http://www.my-site.com/');
+ $this-&gt;assertField('a', 'A default');<strong>
+ $this-&gt;setField('a', 'New value');
+ $this-&gt;click('Go');</strong>
+ }
+}
+</pre>
+ Because we didn't specify a method attribute on the form tag, and
+ didn't specify an action either, the test case will follow
+ the usual browser behaviour of submitting the form data as a <em>GET</em>
+ request back to the same location.
+ SimpleTest tries to emulate typical browser behaviour as much as possible,
+ rather than attempting to catch missing attributes on tags.
+ This is because the target of the testing framework is the PHP application
+ logic, not syntax or other errors in the HTML code.
+ For HTML errors, other tools such as
+ <a href="http://www.w3.org/People/Raggett/tidy/">HTMLTidy</a> should be used.
+ </p>
+ <p>
+ If a field is not present in any form, or if an option is unavailable,
+ then <span class="new_code">WebTestCase::setField()</span> will return
+ <span class="new_code">false</span>.
+ For example, suppose we wish to verify that a "Superuser"
+ option is not present in this form...
+<pre>
+&lt;strong&gt;Select type of user to add:&lt;/strong&gt;
+&lt;select name="type"&gt;
+ &lt;option&gt;Subscriber&lt;/option&gt;
+ &lt;option&gt;Author&lt;/option&gt;
+ &lt;option&gt;Administrator&lt;/option&gt;
+&lt;/select&gt;
+</pre>
+ Which looks like...
+ </p>
+ <p>
+ <form class="demo">
+ <strong>Select type of user to add:</strong>
+ <select name="type">
+ <option>Subscriber</option>
+ <option>Author</option>
+ <option>Administrator</option>
+ </select>
+ </form>
+ </p>
+ <p>
+ The following test will confirm it...
+<pre>
+class SimpleFormTests extends WebTestCase {
+ ...
+ function testNoSuperuserChoiceAvailable() {<strong>
+ $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
+ $this-&gt;assertFalse($this-&gt;setField('type', 'Superuser'));</strong>
+ }
+}
+</pre>
+ The selection will not be changed on a failure to set
+ a widget value.
+ </p>
+ <p>
+ Here is the full list of widgets currently supported...
+ <ul>
+ <li>Text fields, including hidden and password fields.</li>
+ <li>Submit buttons including the button tag, although not yet reset buttons</li>
+ <li>Text area. This includes text wrapping behaviour.</li>
+ <li>Checkboxes, including multiple checkboxes in the same form.</li>
+ <li>Drop down selections, including multiple selects.</li>
+ <li>Radio buttons.</li>
+ <li>Images.</li>
+ </ul>
+ </p>
+ <p>
+ The browser emulation offered by SimpleTest mimics
+ the actions which can be perform by a user on a
+ standard HTML page. Javascript is not supported, and
+ it's unlikely that support will be added any time
+ soon.
+ </p>
+ <p>
+ Of particular note is that the Javascript idiom of
+ passing form results by setting a hidden field cannot
+ be performed using the normal SimpleTest
+ commands. See below for a way to test such forms.
+ </p>
+
+ <p><a class="target" name="multiple"><h2>Fields with multiple values</h2></a></p>
+ <p>
+ SimpleTest can cope with two types of multivalue controls: Multiple
+ selection drop downs, and multiple checkboxes with the same name
+ within a form.
+ The multivalue nature of these means that setting and testing
+ are slightly different.
+ Using checkboxes as an example...
+<pre>
+&lt;form class="demo"&gt;
+ &lt;strong&gt;Create privileges allowed:&lt;/strong&gt;
+ &lt;input type="checkbox" name="crud" value="c" checked&gt;&lt;br&gt;
+ &lt;strong&gt;Retrieve privileges allowed:&lt;/strong&gt;
+ &lt;input type="checkbox" name="crud" value="r" checked&gt;&lt;br&gt;
+ &lt;strong&gt;Update privileges allowed:&lt;/strong&gt;
+ &lt;input type="checkbox" name="crud" value="u" checked&gt;&lt;br&gt;
+ &lt;strong&gt;Destroy privileges allowed:&lt;/strong&gt;
+ &lt;input type="checkbox" name="crud" value="d" checked&gt;&lt;br&gt;
+ &lt;input type="submit" value="Enable Privileges"&gt;
+&lt;/form&gt;
+</pre>
+ Which renders as...
+ </p>
+ <p>
+ <form class="demo">
+ <strong>Create privileges allowed:</strong>
+ <input type="checkbox" name="crud" value="c" checked><br>
+ <strong>Retrieve privileges allowed:</strong>
+ <input type="checkbox" name="crud" value="r" checked><br>
+ <strong>Update privileges allowed:</strong>
+ <input type="checkbox" name="crud" value="u" checked><br>
+ <strong>Destroy privileges allowed:</strong>
+ <input type="checkbox" name="crud" value="d" checked><br>
+ <input type="submit" value="Enable Privileges">
+ </form>
+ </p>
+ <p>
+ If we wish to disable all but the retrieval privileges and
+ submit this information we can do it like this...
+<pre>
+class SimpleFormTests extends WebTestCase {
+ ...<strong>
+ function testDisableNastyPrivileges() {
+ $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
+ $this-&gt;assertField('crud', array('c', 'r', 'u', 'd'));
+ $this-&gt;setField('crud', array('r'));
+ $this-&gt;click('Enable Privileges');
+ }</strong>
+}
+</pre>
+ Instead of setting the field to a single value, we give it a list
+ of values.
+ We do the same when testing expected values.
+ We can then write other test code to confirm the effect of this, perhaps
+ by logging in as that user and attempting an update.
+ </p>
+
+ <p><a class="target" name="hidden-field"><h2>Forms which use javascript to set a hidden field</h2></a></p>
+ <p>
+ If you want to test a form which relies on javascript to set a hidden
+ field, you can't just call setField().
+ The following code will <em>not</em> work:
+<pre>
+class SimpleFormTests extends WebTestCase {
+ function testMyJavascriptForm() {
+ <strong>// This does *not* work</strong>
+ $this-&gt;setField('a_hidden_field', '123');
+ $this-&gt;clickSubmit('OK');
+ }
+}
+</pre>
+ Instead, you need to pass the additional form parameters to the
+ clickSubmit() method:
+<pre>
+class SimpleFormTests extends WebTestCase {
+ function testMyJavascriptForm() {
+ // Pass the hidden field value as an additional POST variable
+ <strong>$this-&gt;clickSubmit('OK', array('a_hidden_field'=&gt;'123'));</strong>
+ }
+
+}
+</pre>
+ </p>
+ <p>
+ Bear in mind that in doing this you're effectively stubbing out a
+ part of your software (the javascript code in the form), and
+ perhaps you might be better off using something like
+ <a href="http://selenium.openqa.org/">Selenium</a> to ensure a complete
+ acceptance test.
+ </p>
+
+ <p><a class="target" name="raw"><h2>Raw posting</h2></a></p>
+ <p>
+ If you want to test a form handler, but have not yet written
+ or do not have access to the form itself, you can create a
+ form submission by hand.
+<pre>
+class SimpleFormTests extends WebTestCase {
+ ...<strong>
+ function testAttemptedHack() {
+ $this-&gt;post(
+ 'http://www.my-site.com/add_user.php',
+ array('type' =&gt; 'superuser'));
+ $this-&gt;assertNoText('user created');
+ }</strong>
+}
+</pre>
+ By adding data to the <span class="new_code">WebTestCase::post()</span>
+ method, we are attempting to fetch the page as a form submission.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
+ gives full detail on the classes and assertions available.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <span class="chosen">Testing forms</span>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/group_test_documentation.html b/vendors/simpletest/docs/en/group_test_documentation.html
new file mode 100644
index 000000000..a0c78843c
--- /dev/null
+++ b/vendors/simpletest/docs/en/group_test_documentation.html
@@ -0,0 +1,386 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest for PHP test suites</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <span class="chosen">Group tests</span>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Test suite documentation</h1>
+ This page...
+ <ul>
+<li>
+ Different ways to <a href="#group">group tests</a> together.
+ </li>
+<li>
+ Combining group tests into <a href="#higher">larger groups</a>.
+ </li>
+<li>
+ Integrating <a href="#legacy">legacy test cases</a> from other
+ types of PHPUnit.
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="group"><h2>Grouping tests into suites</h2></a></p>
+ <p>
+ To run test cases as part of a group, the test cases should really
+ be placed in files without the runner code...
+<pre>
+<strong>&lt;?php
+ require_once('../classes/io.php');
+
+ class FileTester extends UnitTestCase {
+ ...
+ }
+
+ class SocketTester extends UnitTestCase {
+ ...
+ }
+?&gt;</strong>
+</pre>
+ As many cases as needed can appear in a single file.
+ They should include any code they need, such as the library
+ being tested, but none of the simple test libraries.
+ </p>
+ <p>
+ If you have extended any test cases, you can include them
+ as well. In PHP 4...
+<pre>
+&lt;?php
+ require_once('../classes/io.php');
+<strong>
+ class MyFileTestCase extends UnitTestCase {
+ ...
+ }
+ SimpleTest::ignore('MyFileTestCase');</strong>
+
+ class FileTester extends MyFileTestCase { ... }
+
+ class SocketTester extends UnitTestCase { ... }
+?&gt;
+</pre>
+ The <span class="new_code">FileTester</span> class does
+ not contain any actual tests, but is a base class for other
+ test cases.
+ For this reason we use the
+ <span class="new_code">SimpleTestOptions::ignore()</span> directive
+ to tell the upcoming group test to ignore it.
+ This directive can appear anywhere in the file and works
+ when a whole file of test cases is loaded (see below).
+ </p>
+ <p>
+ If you are using PHP 5, you do not need this special directive at all.
+ Simply mark any test cases that should not be run as abstract...
+<pre>
+<strong>abstract</strong> class MyFileTestCase extends UnitTestCase {
+ ...
+}
+
+class FileTester extends MyFileTestCase { ... }
+
+class SocketTester extends UnitTestCase { ... }
+</pre>
+ </p>
+ <p>
+ We will call this sample <em>file_test.php</em>.
+ Next we create a group test file, called say <em>my_group_test.php</em>.
+ You will think of a better name I am sure.
+ </p>
+ <p>
+ We will add the test file using a safe method...
+<pre>
+&lt;?php
+ require_once('simpletest/unit_tester.php');
+ require_once('simpletest/reporter.php');<strong>
+ require_once('file_test.php');
+
+ $test = &amp;new TestSuite('All file tests');
+ $test-&gt;addTestCase(new FileTestCase());
+ $test-&gt;run(new HtmlReporter());</strong>
+?&gt;
+</pre>
+ This instantiates the test case before the test suite is
+ run.
+ This could get a little expensive with a large number of test
+ cases, and can be surprising behaviour.
+ </p>
+ <p>
+ The main problem is that for every test case
+ that we add we will have
+ to <span class="new_code">require_once()</span> the test code
+ file and manually instantiate each and every test case.
+ </p>
+ <p>
+ We can save a lot of typing with...
+<pre>
+&lt;?php
+ require_once('simpletest/unit_tester.php');
+ require_once('simpletest/reporter.php');
+
+ $test = &amp;new TestSuite('All file tests');<strong>
+ $test-&gt;addTestFile('file_test.php');</strong>
+ $test-&gt;run(new HtmlReporter());
+?&amp;gt;
+</pre>
+ What happens here is that the <span class="new_code">TestSuite</span>
+ class has done the <span class="new_code">require_once()</span>
+ for us.
+ It then checks to see if any new test case classes
+ have been created by the new file and automatically adds
+ them to the group test.
+ Now all we have to do is add each new file.
+ </p>
+ <p>
+ No only that, but you can guarantee that the constructor is run
+ just before the first test method and, in PHP 5, the destructor
+ is run just after the last test method.
+ </p>
+ <p>
+ There are two things that could go wrong and which require care...
+ <ol>
+ <li>
+ The file could already have been parsed by PHP, and so no
+ new classes will have been added. You should make
+ sure that the test cases are only included in this file
+ and no others (Note : with the new <cite>autorun</cite>
+ functionnality, this problem has now been solved).
+ </li>
+ <li>
+ New test case extension classes that get included will be
+ placed in the group test and run also.
+ You will need to add a <span class="new_code">SimpleTestOptions::ignore()</span>
+ directive for these classes, or make sure that they are included
+ before the <span class="new_code">TestSuite::addTestFile()</span>
+ line, or make sure that they are abstract classes.
+ </li>
+ </ol>
+ </p>
+
+ <p><a class="target" name="higher"><h2>Composite suites</h2></a></p>
+ <p>
+ The above method places all of the test cases into one large group.
+ For larger projects though this may not be flexible enough; you
+ may want to group the tests in all sorts of ways.
+ </p>
+ <p>
+ To get a more flexible group test we can subclass
+ <span class="new_code">TestSuite</span> and then instantiate it as needed...
+<pre>
+&lt;?php
+ require_once('simpletest/unit_tester.php');
+ require_once('simpletest/reporter.php');
+ <strong>
+ class FileTestSuite extends TestSuite {
+ function FileTestSuite() {
+ $this-&gt;TestSuite('All file tests');
+ $this-&gt;addTestFile('file_test.php');
+ }
+ }</strong>
+?&gt;
+</pre>
+ This effectively names the test in the constructor and then
+ adds our test cases and a single group below.
+ Of course we can add more than one group at this point.
+ We can now invoke the tests from a separate runner file...
+<pre>
+&lt;?php
+ require_once('file_test_suite.php');
+ <strong>
+ $test = &amp;new FileTestSuite();
+ $test-&gt;run(new HtmlReporter());</strong>
+?&gt;
+</pre>
+ ...or we can group them into even larger group tests.
+ We can even mix groups and test cases freely as long as
+ we are careful about double includes...
+<pre>
+&lt;?php
+ <strong>
+ $test = &amp;new BigTestSuite('Big group');
+ $test-&gt;addTestFile('file_test_suite.php');
+ $test-&gt;addTestFile('some_test_case.php');</strong>
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ In the event of a double include, ony the first instance
+ of the test case will be run.
+ </p>
+ <p>
+ If we still wish to run the original group test, and we
+ don't want all of these little runner files, we can
+ put the test runner code around guard bars when we create
+ each group.
+<pre>
+&lt;?php
+ class FileTestSuite extends TestSuite {
+ function FileTestSuite() {
+ $this-&gt;TestSuite('All file tests');
+ $test-&gt;addTestFile('file_test.php');
+ }
+ }
+ <strong>
+ if (! defined('RUNNER')) {
+ define('RUNNER', true);</strong>
+ $test = &amp;new FileTestSuite();
+ $test-&gt;run(new HtmlReporter());
+ }
+?&gt;
+</pre>
+ This approach requires the guard to be set when including
+ the group test file, but this is still less hassle than
+ lots of separate runner files.
+ You include the same guard on the top level tests to make sure
+ that <span class="new_code">run()</span> will run once only
+ from the top level script that has been invoked.
+<pre>
+&lt;?php<strong>
+ define('RUNNER', true);</strong>
+ require_once('file_test_suite.php');
+
+ $test = &amp;new BigTestSuite('Big group');
+ $test-&gt;addTestCase(new FileTestSuite());
+ $test-&gt;addTestCase(...);
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ As with the normal test cases, a <span class="new_code">TestSuite</span> can
+ be loaded with the <span class="new_code">TestSuite::addTestFile()</span> method.
+<pre>
+&lt;?php
+ define('RUNNER', true);
+
+ $test = &amp;new BigTestSuite('Big group');<strong>
+ $test-&gt;addTestFile('file_test_suite.php');
+ $test-&gt;addTestFile(...);</strong>
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ </p>
+
+ <p><a class="target" name="legacy"><h2>Integrating legacy test cases</h2></a></p>
+ <p>
+ If you already have unit tests for your code or are extending external
+ classes that have tests, it is unlikely that all of the test cases
+ are in SimpleTest format.
+ Fortunately it is possible to incorporate test cases from other
+ unit testers directly into SimpleTest group tests.
+ </p>
+ <p>
+ Say we have the following
+ <a href="http://sourceforge.net/projects/phpunit">PhpUnit</a>
+ test case in the file <em>config_test.php</em>...
+<pre>
+<strong>class ConfigFileTest extends TestCase {
+ function ConfigFileTest() {
+ $this-&gt;TestCase('Config file test');
+ }
+
+ function testContents() {
+ $config = new ConfigFile('test.conf');
+ $this-&gt;assertRegexp('/me/', $config-&gt;getValue('username'));
+ }
+}</strong>
+</pre>
+ The group test can recognise this as long as we include
+ the appropriate adapter class before we add the test
+ file...
+<pre>
+&lt;?php
+ require_once('simpletest/unit_tester.php');
+ require_once('simpletest/reporter.php');<strong>
+ require_once('simpletest/adapters/phpunit_test_case.php');</strong>
+
+ $test = &amp;new TestSuite('All file tests');<strong>
+ $test-&gt;addTestFile('config_test.php');</strong>
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ There are only two adapters, the other is for the
+ <a href="http://pear.php.net/manual/en/package.php.phpunit.php">PEAR</a>
+ 1.0 unit tester...
+<pre>
+&lt;?php
+ require_once('simpletest/unit_tester.php');
+ require_once('simpletest/reporter.php');<strong>
+ require_once('simpletest/adapters/pear_test_case.php');</strong>
+
+ $test = &amp;new TestSuite('All file tests');<strong>
+ $test-&gt;addTestFile('some_pear_test_cases.php');</strong>
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ The PEAR test cases can be freely mixed with SimpleTest
+ ones even in the same test file,
+ but you cannot use SimpleTest assertions in the legacy
+ test case versions.
+ This is done as a check that you are not accidently making
+ your test cases completely dependent on SimpleTest.
+ You may want to do a PEAR release of your library for example,
+ which would mean shipping it with valid PEAR::PhpUnit test
+ cases.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <span class="chosen">Group tests</span>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/index.html b/vendors/simpletest/docs/en/index.html
new file mode 100644
index 000000000..03b6c5cef
--- /dev/null
+++ b/vendors/simpletest/docs/en/index.html
@@ -0,0 +1,538 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>
+ Download the Simple Test testing framework -
+ Unit tests and mock objects for PHP
+ </title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<span class="chosen">SimpleTest</span>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Simple Test for PHP</h1>
+ This page...
+ <ul>
+<li>
+ <a href="#unit">Using unit tester</a>
+ with an example.
+ </li>
+<li>
+ <a href="#group">Grouping tests</a>
+ for testing with one click.
+ </li>
+<li>
+ <a href="#mock">Using mock objects</a>
+ to ease testing and gain tighter control.
+ </li>
+<li>
+ <a href="#web">Testing web pages</a>
+ at the browser level.
+ </li>
+</ul>
+<div class="content">
+
+
+ <p>
+ The following assumes that you are familiar with the concept
+ of unit testing as well as the PHP web development language.
+ It is a guide for the impatient new user of
+ <a href="https://sourceforge.net/project/showfiles.php?group_id=76550">SimpleTest</a>.
+ For fuller documentation, especially if you are new
+ to unit testing see the ongoing
+ <a href="unit_test_documentation.html">documentation</a>, and for
+ example test cases see the
+ <a href="http://www.lastcraft.com/first_test_tutorial.php">unit testing tutorial</a>.
+ </p>
+
+ <p><a class="target" name="unit"><h2>Using the tester quickly</h2></a></p>
+ <p>
+ Amongst software testing tools, a unit tester is the one
+ closest to the developer.
+ In the context of agile development the test code sits right
+ next to the source code as both are written simultaneously.
+ In this context SimpleTest aims to be a complete PHP developer
+ test solution and is called "Simple" because it
+ should be easy to use and extend.
+ It wasn't a good choice of name really.
+ It includes all of the typical functions you would expect from
+ <a href="http://www.junit.org/">JUnit</a> and the
+ <a href="http://sourceforge.net/projects/phpunit/">PHPUnit</a>
+ ports, and includes
+ <a href="http://www.mockobjects.com">mock objects</a>.
+ </p>
+ <p>
+ What makes this tool immediately useful to the PHP developer is the internal
+ web browser.
+ This allows tests that navigate web sites, fill in forms and test pages.
+ Being able to write these test in PHP means that it is easy to write
+ integrated tests.
+ An example might be confirming that a user was written to a database
+ after a signing up through the web site.
+ </p>
+ <p>
+ The quickest way to demonstrate SimpleTest is with an example.
+ </p>
+ <p>
+ Let us suppose we are testing a simple file logging class called
+ <span class="new_code">Log</span> in <em>classes/log.php</em>.
+ We start by creating a test script which we will call
+ <em>tests/log_test.php</em> and populate it as follows...
+<pre>
+&lt;?php
+<strong>require_once('simpletest/autorun.php');</strong>
+require_once('../classes/log.php');
+
+class TestOfLogging extends <strong>UnitTestCase</strong> {
+}
+?&gt;
+</pre>
+ Here the <em>simpletest</em> folder is either local or in the path.
+ You would have to edit these locations depending on where you
+ unpacked the toolset.
+ The "autorun.php" file does more than just include the
+ SimpleTest files, it also runs our test for us.
+ </p>
+ <p>
+ The <span class="new_code">TestOfLogging</span> is our first test case and it's
+ currently empty.
+ Each test case is a class that extends one of the SimpleTet base classes
+ and we can have as many of these in the file as we want.
+ </p>
+ <p>
+ With three lines of scaffolding, and our <span class="new_code">Log</span> class
+ include, we have a test suite.
+ No tests though.
+ </p>
+ <p>
+ For our first test, we'll assume that the <span class="new_code">Log</span> class
+ takes the file name to write to in the constructor, and we have
+ a temporary folder in which to place this file...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+require_once('../classes/log.php');
+
+class TestOfLogging extends UnitTestCase {
+ function <strong>testLogCreatesNewFileOnFirstMessage()</strong> {
+ @unlink('/temp/test.log');
+ $log = new Log('/temp/test.log');
+ <strong>$this-&gt;assertFalse(file_exists('/temp/test.log'));</strong>
+ $log-&gt;message('Should write this to a file');
+ <strong>$this-&gt;assertTrue(file_exists('/temp/test.log'));</strong>
+ }
+}
+?&gt;
+</pre>
+ When a test case runs, it will search for any method that
+ starts with the string "test"
+ and execute that method.
+ If the method starts "test", it's a test.
+ Note the very long name <span class="new_code">testLogCreatesNewFileOnFirstMessage()</span>.
+ This is considered good style and makes the test output more readable.
+ </p>
+ <p>
+ We would normally have more than one test method in a test case,
+ but that's for later.
+ </p>
+ <p>
+ Assertions within the test methods trigger messages to the
+ test framework which displays the result immediately.
+ This immediate response is important, not just in the event
+ of the code causing a crash, but also so that
+ <span class="new_code">print</span> statements can display
+ their debugging content right next to the assertion concerned.
+ </p>
+ <p>
+ To see these results we have to actually run the tests.
+ No other code is necessary - we can just open the page
+ with our browser.
+ </p>
+ <p>
+ On failure the display looks like this...
+ <div class="demo">
+ <h1>TestOfLogging</h1>
+ <span class="fail">Fail</span>: testLogCreatesNewFileOnFirstMessage-&gt;True assertion failed.<br>
+ <div style="padding: 8px; margin-top: 1em; background-color: red; color: white;">1/1 test cases complete.
+ <strong>1</strong> passes and <strong>1</strong> fails.</div>
+ </div>
+ ...and if it passes like this...
+ <div class="demo">
+ <h1>TestOfLogging</h1>
+ <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
+ <strong>2</strong> passes and <strong>0</strong> fails.</div>
+ </div>
+ And if you get this...
+ <div class="demo">
+ <b>Fatal error</b>: Failed opening required '../classes/log.php' (include_path='') in <b>/home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php</b> on line <b>7</b>
+ </div>
+ it means you're missing the <em>classes/Log.php</em> file that could look like...
+<pre>
+&lt;?php<strong>
+class Log {
+ function Log($file_path) {
+ }
+
+ function message() {
+ }
+}</strong>
+?&gt;
+</pre>
+ It's fun to write the code after the test.
+ More than fun even -
+ this system is called "Test Driven Development".
+ </p>
+ <p>
+ For more information about <span class="new_code">UnitTestCase</span>, see
+ the <a href="unit_test_documentation.html">unit test documentation</a>.
+ </p>
+
+ <p><a class="target" name="group"><h2>Building test suites</h2></a></p>
+ <p>
+ It is unlikely in a real application that we will only ever run
+ one test case.
+ This means that we need a way of grouping cases into a test
+ script that can, if need be, run every test for the application.
+ </p>
+ <p>
+ Our first step is to create a new file called <em>tests/all_tests.php</em>
+ and insert the following code...
+<pre>
+&lt;?php
+<strong>require_once('simpletest/autorun.php');</strong>
+
+class AllTests extends <strong>TestSuite</strong> {
+ function AllTests() {
+ $this-&gt;TestSuite(<strong>'All tests'</strong>);
+ <strong>$this-&gt;addFile('log_test.php');</strong>
+ }
+}
+?&gt;
+</pre>
+ The "autorun" include allows our upcoming test suite
+ to be run just by invoking this script.
+ </p>
+ <p>
+ The <span class="new_code">TestSuite</span> subclass must chain it's constructor.
+ This limitation will be removed in future versions.
+ </p>
+ <p>
+ The method <span class="new_code">TestSuite::addFile()</span>
+ will include the test case file and read any new classes
+ that are descended from <span class="new_code">SimpleTestCase</span>.
+ <span class="new_code">UnitTestCase</span> is just one example of a class derived from
+ <span class="new_code">SimpleTestCase</span>, and you can create your own.
+ <span class="new_code">TestSuite::addFile()</span> can include other test suites.
+ </p>
+ <p>
+ The class will not be instantiated yet.
+ When the test suite runs it will construct each instance once
+ it reaches that test, then destroy it straight after.
+ This means that the constructor is run just before each run
+ of that test case, and the destructor is run before the next test case starts.
+ </p>
+ <p>
+ It is common to group test case code into superclasses which are not
+ supposed to run, but become the base classes of other tests.
+ For "autorun" to work properly the test case file should not blindly run
+ any other test case extensions that do not actually run tests.
+ This could result in extra test cases being counted during the test
+ run.
+ Hardly a major problem, but to avoid this inconvenience simply mark your
+ base class as <span class="new_code">abstract</span>.
+ SimpleTest won't run abstract classes.
+ If you are still using PHP4, then
+ a <span class="new_code">SimpleTestOptions::ignore()</span> directive
+ somewhere in the test case file will have the same effect.
+ </p>
+ <p>
+ Also, the test case file should not have been included
+ elsewhere or no cases will be added to this group test.
+ This would be a more serious error as if the test case classes are
+ already loaded by PHP the <span class="new_code">TestSuite::addFile()</span>
+ method will not detect them.
+ </p>
+ <p>
+ To display the results it is necessary only to invoke
+ <em>tests/all_tests.php</em> from the web server or the command line.
+ </p>
+ <p>
+ For more information about building test suites,
+ see the <a href="group_test_documentation.html">test suite documentation</a>.
+ </p>
+
+ <p><a class="target" name="mock"><h2>Using mock objects</h2></a></p>
+ <p>
+ Let's move further into the future and do something really complicated.
+ </p>
+ <p>
+ Assume that our logging class is tested and completed.
+ Assume also that we are testing another class that is
+ required to write log messages, say a
+ <span class="new_code">SessionPool</span>.
+ We want to test a method that will probably end up looking
+ like this...
+<pre><strong>
+class SessionPool {
+ ...
+ function logIn($username) {
+ ...
+ $this-&gt;_log-&gt;message("User $username logged in.");
+ ...
+ }
+ ...
+}
+</strong>
+</pre>
+ In the spirit of reuse, we are using our
+ <span class="new_code">Log</span> class.
+ A conventional test case might look like this...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+require_once('../classes/log.php');
+<strong>require_once('../classes/session_pool.php');</strong>
+
+class <strong>TestOfSessionLogging</strong> extends UnitTestCase {
+
+ function setUp() {
+ <strong>@unlink('/temp/test.log');</strong>
+ }
+
+ function tearDown() {
+ <strong>@unlink('/temp/test.log');</strong>
+ }
+
+ function testLoggingInIsLogged() {
+ <strong>$log = new Log('/temp/test.log');
+ $session_pool = &amp;new SessionPool($log);
+ $session_pool-&gt;logIn('fred');</strong>
+ $messages = file('/temp/test.log');
+ $this-&gt;assertEqual($messages[0], "User fred logged in.<strong>\n</strong>");
+ }
+}
+?&gt;
+</pre>
+ We'll explain the <span class="new_code">setUp()</span> and <span class="new_code">tearDown()</span>
+ methods later.
+ </p>
+ <p>
+ This test case design is not all bad, but it could be improved.
+ We are spending time fiddling with log files which are
+ not part of our test.
+ We have created close ties with the <span class="new_code">Log</span> class and
+ this test.
+ What if we don't use files any more, but use ths
+ <em>syslog</em> library instead?
+ It means that our <span class="new_code">TestOfSessionLogging</span> test will
+ fail, even thouh it's not testing Logging.
+ </p>
+ <p>
+ It's fragile in smaller ways too.
+ Did you notice the extra carriage return in the message?
+ Was that added by the logger?
+ What if it also added a time stamp or other data?
+ </p>
+ <p>
+ The only part that we really want to test is that a particular
+ message was sent to the logger.
+ We can reduce coupling if we pass in a fake logging class
+ that simply records the message calls for testing, but
+ takes no action.
+ It would have to look exactly like our original though.
+ </p>
+ <p>
+ If the fake object doesn't write to a file then we save on deleting
+ the file before and after each test. We could save even more
+ test code if the fake object would kindly run the assertion for us.
+ <p>
+ </p>
+ Too good to be true?
+ We can create such an object easily...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+require_once('../classes/log.php');
+require_once('../classes/session_pool.php');
+
+<strong>Mock::generate('Log');</strong>
+
+class TestOfSessionLogging extends UnitTestCase {
+
+ function testLoggingInIsLogged() {<strong>
+ $log = &amp;new MockLog();
+ $log-&gt;expectOnce('message', array('User fred logged in.'));</strong>
+ $session_pool = &amp;new SessionPool(<strong>$log</strong>);
+ $session_pool-&gt;logIn('fred');
+ }
+}
+?&gt;
+</pre>
+ The <span class="new_code">Mock::generate()</span> call code generated a new class
+ called <span class="new_code">MockLog</span>.
+ This looks like an identical clone, except that we can wire test code
+ to it.
+ That's what <span class="new_code">expectOnce()</span> does.
+ It says that if <span class="new_code">message()</span> is ever called on me, it had
+ better be with the parameter "User fred logged in.".
+ </p>
+ <p>
+ The test will be triggered when the call to
+ <span class="new_code">message()</span> is invoked on the
+ <span class="new_code">MockLog</span> object by <span class="new_code">SessionPool::logIn()</span> code.
+ The mock call will trigger a parameter comparison and then send the
+ resulting pass or fail event to the test display.
+ Wildcards can be included here too, so you don't have to test every parameter of
+ a call when you only want to test one.
+ </p>
+ <p>
+ If the mock reaches the end of the test case without the
+ method being called, the <span class="new_code">expectOnce()</span>
+ expectation will trigger a test failure.
+ In other words the mocks can detect the absence of
+ behaviour as well as the presence.
+ </p>
+ <p>
+ The mock objects in the SimpleTest suite can have arbitrary
+ return values set, sequences of returns, return values
+ selected according to the incoming arguments, sequences of
+ parameter expectations and limits on the number of times
+ a method is to be invoked.
+ </p>
+ <p>
+ For more information about mocking and stubbing, see the
+ <a href="mock_objects_documentation.html">mock objects documentation</a>.
+ </p>
+
+ <p><a class="target" name="web"><h2>Web page testing</h2></a></p>
+ <p>
+ One of the requirements of web sites is that they produce web
+ pages.
+ If you are building a project top-down and you want to fully
+ integrate testing along the way then you will want a way of
+ automatically navigating a site and examining output for
+ correctness.
+ This is the job of a web tester.
+ </p>
+ <p>
+ The web testing in SimpleTest is fairly primitive, as there is
+ no JavaScript.
+ Most other browser operations are simulated.
+ </p>
+ <p>
+ To give an idea here is a trivial example where a home
+ page is fetched, from which we navigate to an "about"
+ page and then test some client determined content.
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+<strong>require_once('simpletest/web_tester.php');</strong>
+
+class TestOfAbout extends <strong>WebTestCase</strong> {
+ function testOurAboutPageGivesFreeReignToOurEgo() {
+ <strong>$this-&gt;get('http://test-server/index.php');
+ $this-&gt;click('About');
+ $this-&gt;assertTitle('About why we are so great');
+ $this-&gt;assertText('We are really great');</strong>
+ }
+}
+?&gt;
+</pre>
+ With this code as an acceptance test, you can ensure that
+ the content always meets the specifications of both the
+ developers, and the other project stakeholders.
+ </p>
+ <p>
+ You can navigate forms too...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+require_once('simpletest/web_tester.php');
+
+class TestOfRankings extends WebTestCase {
+ function testWeAreTopOfGoogle() {
+ $this-&gt;get('http://google.com/');
+ $this-&gt;setField('q', 'simpletest');
+ $this-&gt;click("I'm Feeling Lucky");
+ $this-&gt;assertTitle('SimpleTest - Unit Testing for PHP');
+ }
+}
+?&gt;
+</pre>
+ ...although this could violate Google's(tm) terms and conditions.
+ </p>
+ <p>
+ For more information about web testing, see the
+ <a href="browser_documentation.html">scriptable
+ browser documentation</a> and the
+ <a href="web_tester_documentation.html">WebTestCase</a>.
+ </p>
+ <p>
+ <a href="http://sourceforge.net/projects/simpletest/"><img src="http://sourceforge.net/sflogo.php?group_id=76550&amp;type=5" width="210" height="62" border="0" alt="SourceForge.net Logo"></a>
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ <a href="https://sourceforge.net/project/showfiles.php?group_id=76550&amp;release_id=153280">Download PHP Simple Test</a>
+ from <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
+ gives full detail on the classes and assertions available.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<span class="chosen">SimpleTest</span>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/mock_objects_documentation.html b/vendors/simpletest/docs/en/mock_objects_documentation.html
new file mode 100644
index 000000000..c3d002277
--- /dev/null
+++ b/vendors/simpletest/docs/en/mock_objects_documentation.html
@@ -0,0 +1,757 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest for PHP mock objects documentation</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <span class="chosen">Mock objects</span>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Mock objects documentation</h1>
+ This page...
+ <ul>
+<li>
+ <a href="#what">What are mock objects?</a>
+ </li>
+<li>
+ <a href="#creation">Creating mock objects</a>.
+ </li>
+<li>
+ <a href="#stub">Mocks as actors</a> or stubs.
+ </li>
+<li>
+ <a href="#expectations">Mocks as critics</a> with expectations.
+ </li>
+<li>
+ <a href="#approaches">Other approaches</a> including mock libraries.
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="what"><h2>What are mock objects?</h2></a></p>
+ <p>
+ Mock objects have two roles during a test case: actor and critic.
+ </p>
+ <p>
+ The actor behaviour is to simulate objects that are difficult to
+ set up or time consuming to set up for a test.
+ The classic example is a database connection.
+ Setting up a test database at the start of each test would slow
+ testing to a crawl and would require the installation of the
+ database engine and test data on the test machine.
+ If we can simulate the connection and return data of our
+ choosing we not only win on the pragmatics of testing, but can
+ also feed our code spurious data to see how it responds.
+ We can simulate databases being down or other extremes
+ without having to create a broken database for real.
+ In other words, we get greater control of the test environment.
+ </p>
+ <p>
+ If mock objects only behaved as actors they would simply be
+ known as server stubs.
+ This was originally a pattern named by Robert Binder (Testing
+ object-oriented systems: models, patterns, and tools,
+ Addison-Wesley) in 1999.
+ </p>
+ <p>
+ A server stub is a simulation of an object or component.
+ It should exactly replace a component in a system for test
+ or prototyping purposes, but remain lightweight.
+ This allows tests to run more quickly, or if the simulated
+ class has not been written, to run at all.
+ </p>
+ <p>
+ However, the mock objects not only play a part (by supplying chosen
+ return values on demand) they are also sensitive to the
+ messages sent to them (via expectations).
+ By setting expected parameters for a method call they act
+ as a guard that the calls upon them are made correctly.
+ If expectations are not met they save us the effort of
+ writing a failed test assertion by performing that duty on our
+ behalf.
+ </p>
+ <p>
+ In the case of an imaginary database connection they can
+ test that the query, say SQL, was correctly formed by
+ the object that is using the connection.
+ Set them up with fairly tight expectations and you will
+ hardly need manual assertions at all.
+ </p>
+
+ <p><a class="target" name="creation"><h2>Creating mock objects</h2></a></p>
+ <p>
+ In the same way that we create server stubs, all we need is an
+ existing class, say a database connection that looks like this...
+<pre>
+<strong>class DatabaseConnection {
+ function DatabaseConnection() {
+ }
+
+ function query() {
+ }
+
+ function selectQuery() {
+ }
+}</strong>
+</pre>
+ The class does not need to have been implemented yet.
+ To create a mock version of the class we need to include the
+ mock object library and run the generator...
+<pre>
+<strong>require_once('simpletest/unit_tester.php');
+require_once('simpletest/mock_objects.php');
+require_once('database_connection.php');
+
+Mock::generate('DatabaseConnection');</strong>
+</pre>
+ This generates a clone class called
+ <span class="new_code">MockDatabaseConnection</span>.
+ We can now create instances of the new class within
+ our test case...
+<pre>
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/mock_objects.php');
+require_once('database_connection.php');
+
+Mock::generate('DatabaseConnection');
+<strong>
+class MyTestCase extends UnitTestCase {
+
+ function testSomething() {
+ $connection = &amp;new MockDatabaseConnection();
+ }
+}</strong>
+</pre>
+ Unlike the generated stubs the mock constructor needs a reference
+ to the test case so that it can dispatch passes and failures while
+ checking its expectations.
+ This means that mock objects can only be used within test cases.
+ Despite this their extra power means that stubs are hardly ever used
+ if mocks are available.
+ </p>
+ <p>
+ <a class="target" name="stub"><h2>Mocks as actors</h2></a>
+ </p>
+ <p>
+ The mock version of a class has all the methods of the original,
+ so that operations like
+ <span class="new_code">$connection-&gt;query()</span> are still
+ legal.
+ The return value will be <span class="new_code">null</span>,
+ but we can change that with...
+<pre>
+<strong>$connection-&gt;setReturnValue('query', 37)</strong>
+</pre>
+ Now every time we call
+ <span class="new_code">$connection-&gt;query()</span> we get
+ the result of 37.
+ We can set the return value to anything, say a hash of
+ imaginary database results or a list of persistent objects.
+ Parameters are irrelevant here, we always get the same
+ values back each time once they have been set up this way.
+ That may not sound like a convincing replica of a
+ database connection, but for the half a dozen lines of
+ a test method it is usually all you need.
+ </p>
+ <p>
+ We can also add extra methods to the mock when generating it
+ and choose our own class name...
+<pre>
+<strong>Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));</strong>
+</pre>
+ Here the mock will behave as if the <span class="new_code">setOptions()</span>
+ existed in the original class.
+ This is handy if a class has used the PHP <span class="new_code">overload()</span>
+ mechanism to add dynamic methods.
+ You can create a special mock to simulate this situation.
+ </p>
+ <p>
+ Things aren't always that simple though.
+ One common problem is iterators, where constantly returning
+ the same value could cause an endless loop in the object
+ being tested.
+ For these we need to set up sequences of values.
+ Let's say we have a simple iterator that looks like this...
+<pre>
+class Iterator {
+ function Iterator() {
+ }
+
+ function next() {
+ }
+}
+</pre>
+ This is about the simplest iterator you could have.
+ Assuming that this iterator only returns text until it
+ reaches the end, when it returns false, we can simulate it
+ with...
+<pre>
+Mock::generate('Iterator');
+
+class IteratorTest extends UnitTestCase() {
+
+ function testASequence() {<strong>
+ $iterator = &amp;new MockIterator();
+ $iterator-&gt;setReturnValue('next', false);
+ $iterator-&gt;setReturnValueAt(0, 'next', 'First string');
+ $iterator-&gt;setReturnValueAt(1, 'next', 'Second string');</strong>
+ ...
+ }
+}
+</pre>
+ When <span class="new_code">next()</span> is called on the
+ mock iterator it will first return "First string",
+ on the second call "Second string" will be returned
+ and on any other call <span class="new_code">false</span> will
+ be returned.
+ The sequenced return values take precedence over the constant
+ return value.
+ The constant one is a kind of default if you like.
+ </p>
+ <p>
+ Another tricky situation is an overloaded
+ <span class="new_code">get()</span> operation.
+ An example of this is an information holder with name/value pairs.
+ Say we have a configuration class like...
+<pre>
+class Configuration {
+ function Configuration() {
+ }
+
+ function getValue($key) {
+ }
+}
+</pre>
+ This is a classic situation for using mock objects as
+ actual configuration will vary from machine to machine,
+ hardly helping the reliability of our tests if we use it
+ directly.
+ The problem though is that all the data comes through the
+ <span class="new_code">getValue()</span> method and yet
+ we want different results for different keys.
+ Luckily the mocks have a filter system...
+<pre>
+<strong>$config = &amp;new MockConfiguration();
+$config-&gt;setReturnValue('getValue', 'primary', array('db_host'));
+$config-&gt;setReturnValue('getValue', 'admin', array('db_user'));
+$config-&gt;setReturnValue('getValue', 'secret', array('db_password'));</strong>
+</pre>
+ The extra parameter is a list of arguments to attempt
+ to match.
+ In this case we are trying to match only one argument which
+ is the look up key.
+ Now when the mock object has the
+ <span class="new_code">getValue()</span> method invoked
+ like this...
+<pre>
+$config-&gt;getValue('db_user')
+</pre>
+ ...it will return "admin".
+ It finds this by attempting to match the calling arguments
+ to its list of returns one after another until
+ a complete match is found.
+ </p>
+ <p>
+ You can set a default argument argument like so...
+<pre><strong>
+$config-&gt;setReturnValue('getValue', false, array('*'));</strong>
+</pre>
+ This is not the same as setting the return value without
+ any argument requirements like this...
+<pre><strong>
+$config-&gt;setReturnValue('getValue', false);</strong>
+</pre>
+ In the first case it will accept any single argument,
+ but exactly one is required.
+ In the second case any number of arguments will do and
+ it acts as a catchall after all other matches.
+ Note that if we add further single parameter options after
+ the wildcard in the first case, they will be ignored as the wildcard
+ will match first.
+ With complex parameter lists the ordering could be important
+ or else desired matches could be masked by earlier wildcard
+ ones.
+ Declare the most specific matches first if you are not sure.
+ </p>
+ <p>
+ There are times when you want a specific object to be
+ dished out by the mock rather than a copy.
+ The PHP4 copy semantics force us to use a different method
+ for this.
+ You might be simulating a container for example...
+<pre>
+class Thing {
+}
+
+class Vector {
+ function Vector() {
+ }
+
+ function get($index) {
+ }
+}
+</pre>
+ In this case you can set a reference into the mock's
+ return list...
+<pre>
+$thing = &amp;new Thing();<strong>
+$vector = &amp;new MockVector();
+$vector-&gt;setReturnReference('get', $thing, array(12));</strong>
+</pre>
+ With this arrangement you know that every time
+ <span class="new_code">$vector-&gt;get(12)</span> is
+ called it will return the same
+ <span class="new_code">$thing</span> each time.
+ This is compatible with PHP5 as well.
+ </p>
+ <p>
+ These three factors, timing, parameters and whether to copy,
+ can be combined orthogonally.
+ For example...
+<pre>
+$complex = &amp;new MockComplexThing();
+$stuff = &amp;new Stuff();<strong>
+$complex-&gt;setReturnReferenceAt(3, 'get', $stuff, array('*', 1));</strong>
+</pre>
+ This will return the <span class="new_code">$stuff</span> only on the third
+ call and only if two parameters were set the second of
+ which must be the integer 1.
+ That should cover most simple prototyping situations.
+ </p>
+ <p>
+ A final tricky case is one object creating another, known
+ as a factory pattern.
+ Suppose that on a successful query to our imaginary
+ database, a result set is returned as an iterator with
+ each call to <span class="new_code">next()</span> giving
+ one row until false.
+ This sounds like a simulation nightmare, but in fact it can all
+ be mocked using the mechanics above.
+ </p>
+ <p>
+ Here's how...
+<pre>
+Mock::generate('DatabaseConnection');
+Mock::generate('ResultIterator');
+
+class DatabaseTest extends UnitTestCase {
+
+ function testUserFinder() {<strong>
+ $result = &amp;new MockResultIterator();
+ $result-&gt;setReturnValue('next', false);
+ $result-&gt;setReturnValueAt(0, 'next', array(1, 'tom'));
+ $result-&gt;setReturnValueAt(1, 'next', array(3, 'dick'));
+ $result-&gt;setReturnValueAt(2, 'next', array(6, 'harry'));
+
+ $connection = &amp;new MockDatabaseConnection();
+ $connection-&gt;setReturnValue('query', false);
+ $connection-&gt;setReturnReference(
+ 'query',
+ $result,
+ array('select id, name from users'));</strong>
+
+ $finder = &amp;new UserFinder($connection);
+ $this-&gt;assertIdentical(
+ $finder-&gt;findNames(),
+ array('tom', 'dick', 'harry'));
+ }
+}
+</pre>
+ Now only if our
+ <span class="new_code">$connection</span> is called with the correct
+ <span class="new_code">query()</span> will the
+ <span class="new_code">$result</span> be returned that is
+ itself exhausted after the third call to <span class="new_code">next()</span>.
+ This should be enough
+ information for our <span class="new_code">UserFinder</span> class,
+ the class actually
+ being tested here, to come up with goods.
+ A very precise test and not a real database in sight.
+ </p>
+
+ <p><a class="target" name="expectations"><h2>Mocks as critics</h2></a></p>
+ <p>
+ Although the server stubs approach insulates your tests from
+ real world disruption, it is only half the benefit.
+ You can have the class under test receiving the required
+ messages, but is your new class sending correct ones?
+ Testing this can get messy without a mock objects library.
+ </p>
+ <p>
+ By way of example, suppose we have a
+ <span class="new_code">SessionPool</span> class that we
+ want to add logging to.
+ Rather than grow the original class into something more
+ complicated, we want to add this behaviour with a decorator (GOF).
+ The <span class="new_code">SessionPool</span> code currently looks
+ like this...
+<pre>
+<strong>class SessionPool {
+ function SessionPool() {
+ ...
+ }
+
+ function &amp;findSession($cookie) {
+ ...
+ }
+ ...
+}
+
+class Session {
+ ...
+}</strong>
+</pre>
+ While our logging code looks like this...
+<pre>
+<strong>
+class Log {
+ function Log() {
+ ...
+ }
+
+ function message() {
+ ...
+ }
+}
+
+class LoggingSessionPool {
+ function LoggingSessionPool(&amp;$session_pool, &amp;$log) {
+ ...
+ }
+
+ function &amp;findSession($cookie) {
+ ...
+ }
+ ...
+}</strong>
+</pre>
+ Out of all of this, the only class we want to test here
+ is the <span class="new_code">LoggingSessionPool</span>.
+ In particular we would like to check that the
+ <span class="new_code">findSession()</span> method is
+ called with the correct session ID in the cookie and that
+ it sent the message "Starting session $cookie"
+ to the logger.
+ </p>
+ <p>
+ Despite the fact that we are testing only a few lines of
+ production code, here is what we would have to do in a
+ conventional test case:
+ <ol>
+ <li>Create a log object.</li>
+ <li>Set a directory to place the log file.</li>
+ <li>Set the directory permissions so we can write the log.</li>
+ <li>Create a <span class="new_code">SessionPool</span> object.</li>
+ <li>Hand start a session, which probably does lot's of things.</li>
+ <li>Invoke <span class="new_code">findSession()</span>.</li>
+ <li>Read the new Session ID (hope there is an accessor!).</li>
+ <li>Raise a test assertion to confirm that the ID matches the cookie.</li>
+ <li>Read the last line of the log file.</li>
+ <li>Pattern match out the extra logging timestamps, etc.</li>
+ <li>Assert that the session message is contained in the text.</li>
+ </ol>
+ It is hardly surprising that developers hate writing tests
+ when they are this much drudgery.
+ To make things worse, every time the logging format changes or
+ the method of creating new sessions changes, we have to rewrite
+ parts of this test even though this test does not officially
+ test those parts of the system.
+ We are creating headaches for the writers of these other classes.
+ </p>
+ <p>
+ Instead, here is the complete test method using mock object magic...
+<pre>
+Mock::generate('Session');
+Mock::generate('SessionPool');
+Mock::generate('Log');
+
+class LoggingSessionPoolTest extends UnitTestCase {
+ ...
+ function testFindSessionLogging() {<strong>
+ $session = &amp;new MockSession();
+ $pool = &amp;new MockSessionPool();
+ $pool-&gt;setReturnReference('findSession', $session);
+ $pool-&gt;expectOnce('findSession', array('abc'));
+
+ $log = &amp;new MockLog();
+ $log-&gt;expectOnce('message', array('Starting session abc'));
+
+ $logging_pool = &amp;new LoggingSessionPool($pool, $log);
+ $this-&gt;assertReference($logging_pool-&gt;findSession('abc'), $session);</strong>
+ }
+}
+</pre>
+ We start by creating a dummy session.
+ We don't have to be too fussy about this as the check
+ for which session we want is done elsewhere.
+ We only need to check that it was the same one that came
+ from the session pool.
+ </p>
+ <p>
+ <span class="new_code">findSession()</span> is a factory
+ method the simulation of which is described <a href="#stub">above</a>.
+ The point of departure comes with the first
+ <span class="new_code">expectOnce()</span> call.
+ This line states that whenever
+ <span class="new_code">findSession()</span> is invoked on the
+ mock, it will test the incoming arguments.
+ If it receives the single argument of a string "abc"
+ then a test pass is sent to the unit tester, otherwise a fail is
+ generated.
+ This was the part where we checked that the right session was asked for.
+ The argument list follows the same format as the one for setting
+ return values.
+ You can have wildcards and sequences and the order of
+ evaluation is the same.
+ </p>
+ <p>
+ We use the same pattern to set up the mock logger.
+ We tell it that it should have
+ <span class="new_code">message()</span> invoked
+ once only with the argument "Starting session abc".
+ By testing the calling arguments, rather than the logger output,
+ we insulate the test from any display changes in the logger.
+ </p>
+ <p>
+ We start to run our tests when we create the new
+ <span class="new_code">LoggingSessionPool</span> and feed
+ it our preset mock objects.
+ Everything is now under our control.
+ </p>
+ <p>
+ This is still quite a bit of test code, but the code is very
+ strict.
+ If it still seems rather daunting there is a lot less of it
+ than if we tried this without mocks and this particular test,
+ interactions rather than output, is always more work to set
+ up.
+ More often you will be testing more complex situations without
+ needing this level or precision.
+ Also some of this can be refactored into a test case
+ <span class="new_code">setUp()</span> method.
+ </p>
+ <p>
+ Here is the full list of expectations you can set on a mock object
+ in <a href="http://www.lastcraft.com/simple_test.php">SimpleTest</a>...
+ <table>
+<thead>
+ <tr>
+<th>Expectation</th>
+<th>Needs <span class="new_code">tally()</span>
+</th>
+</tr>
+ </thead>
+<tbody>
+<tr>
+ <td><span class="new_code">expect($method, $args)</span></td>
+ <td style="text-align: center">No</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectAt($timing, $method, $args)</span></td>
+ <td style="text-align: center">No</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectCallCount($method, $count)</span></td>
+ <td style="text-align: center">Yes</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectMaximumCallCount($method, $count)</span></td>
+ <td style="text-align: center">No</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectMinimumCallCount($method, $count)</span></td>
+ <td style="text-align: center">Yes</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectNever($method)</span></td>
+ <td style="text-align: center">No</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectOnce($method, $args)</span></td>
+ <td style="text-align: center">Yes</td>
+ </tr>
+ <tr>
+ <td><span class="new_code">expectAtLeastOnce($method, $args)</span></td>
+ <td style="text-align: center">Yes</td>
+ </tr>
+ </tbody>
+</table>
+ Where the parameters are...
+ <dl>
+ <dt class="new_code">$method</dt>
+ <dd>The method name, as a string, to apply the condition to.</dd>
+ <dt class="new_code">$args</dt>
+ <dd>
+ The arguments as a list. Wildcards can be included in the same
+ manner as for <span class="new_code">setReturn()</span>.
+ This argument is optional for <span class="new_code">expectOnce()</span>
+ and <span class="new_code">expectAtLeastOnce()</span>.
+ </dd>
+ <dt class="new_code">$timing</dt>
+ <dd>
+ The only point in time to test the condition.
+ The first call starts at zero.
+ </dd>
+ <dt class="new_code">$count</dt>
+ <dd>The number of calls expected.</dd>
+ </dl>
+ The method <span class="new_code">expectMaximumCallCount()</span>
+ is slightly different in that it will only ever generate a failure.
+ It is silent if the limit is never reached.
+ </p>
+ <p>
+ Also if you have juste one call in your test, make sure you're using
+ <span class="new_code">expectOnce</span>.<br>
+ Using <span class="new_code">$mocked-&gt;expectAt(0, 'method', 'args);</span>
+ on its own will not be catched :
+ checking the arguments and the overall call count
+ are currently independant.
+ </p>
+ <p>
+ Like the assertions within test cases, all of the expectations
+ can take a message override as an extra parameter.
+ Also the original failure message can be embedded in the output
+ as "%s".
+ </p>
+
+ <p><a class="target" name="approaches"><h2>Other approaches</h2></a></p>
+ <p>
+ There are three approaches to creating mocks including the one
+ that SimpleTest employs.
+ Coding them by hand using a base class, generating them to
+ a file and dynamically generating them on the fly.
+ </p>
+ <p>
+ Mock objects generated with <a href="simple_test.html">SimpleTest</a>
+ are dynamic.
+ They are created at run time in memory, using
+ <span class="new_code">eval()</span>, rather than written
+ out to a file.
+ This makes the mocks easy to create, a one liner,
+ especially compared with hand
+ crafting them in a parallel class hierarchy.
+ The problem is that the behaviour is usually set up in the tests
+ themselves.
+ If the original objects change the mock versions
+ that the tests rely on can get out of sync.
+ This can happen with the parallel hierarchy approach as well,
+ but is far more quickly detected.
+ </p>
+ <p>
+ The solution, of course, is to add some real integration
+ tests.
+ You don't need very many and the convenience gained
+ from the mocks more than outweighs the small amount of
+ extra testing.
+ You cannot trust code that was only tested with mocks.
+ </p>
+ <p>
+ If you are still determined to build static libraries of mocks
+ because you want to simulate very specific behaviour, you can
+ achieve the same effect using the SimpleTest class generator.
+ In your library file, say <em>mocks/connection.php</em> for a
+ database connection, create a mock and inherit to override
+ special methods or add presets...
+<pre>
+&lt;?php
+ require_once('simpletest/mock_objects.php');
+ require_once('../classes/connection.php');
+<strong>
+ Mock::generate('Connection', 'BasicMockConnection');
+ class MockConnection extends BasicMockConnection {
+ function MockConnection() {
+ $this-&gt;BasicMockConnection();
+ $this-&gt;setReturn('query', false);
+ }
+ }</strong>
+?&gt;
+</pre>
+ The generate call tells the class generator to create
+ a class called <span class="new_code">BasicMockConnection</span>
+ rather than the usual <span class="new_code">MockConnection</span>.
+ We then inherit from this to get our version of
+ <span class="new_code">MockConnection</span>.
+ By intercepting in this way we can add behaviour, here setting
+ the default value of <span class="new_code">query()</span> to be false.
+ By using the default name we make sure that the mock class
+ generator will not recreate a different one when invoked elsewhere in the
+ tests.
+ It never creates a class if it already exists.
+ As long as the above file is included first then all tests
+ that generated <span class="new_code">MockConnection</span> should
+ now be using our one instead.
+ If we don't get the order right and the mock library
+ creates one first then the class creation will simply fail.
+ </p>
+ <p>
+ Use this trick if you find you have a lot of common mock behaviour
+ or you are getting frequent integration problems at later
+ stages of testing.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ The original
+ <a href="http://www.mockobjects.com/">Mock objects</a> paper.
+ </li>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest home page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <span class="chosen">Mock objects</span>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/overview.html b/vendors/simpletest/docs/en/overview.html
new file mode 100644
index 000000000..5bed89e51
--- /dev/null
+++ b/vendors/simpletest/docs/en/overview.html
@@ -0,0 +1,486 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>
+ Overview and feature list for the SimpleTest PHP unit tester and web tester
+ </title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <span class="chosen">Overview</span>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Overview of SimpleTest</h1>
+ This page...
+ <ul>
+<li>
+ <a href="#summary">Quick summary</a>
+ of the SimpleTest tool for PHP.
+ </li>
+<li>
+ <a href="#features">List of features</a>,
+ both current ones and those planned.
+ </li>
+<li>
+ There are plenty of <a href="#resources">unit testing resources</a>
+ on the web.
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="summary"><h2>What is SimpleTest?</h2></a></p>
+ <p>
+ The heart of SimpleTest is a testing framework built around
+ test case classes.
+ These are written as extensions of base test case classes,
+ each extended with methods that actually contain test code.
+ Top level test scripts then invoke the <span class="new_code">run()</span>
+ methods on every one of these test cases in order.
+ Each test method is written to invoke various assertions that
+ the developer expects to be true such as
+ <span class="new_code">assertEqual()</span>.
+ If the expectation is correct, then a successful result is dispatched to the
+ observing test reporter, but any failure triggers an alert
+ and a description of the mismatch.
+ </p>
+ <p>
+ A <a href="unit_test_documentation.html">test case</a> looks like this...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+
+class <strong>MyTestCase</strong> extends UnitTestCase {
+ <strong>
+ function testCreatedLogFile() {
+ $log = &amp;new Log('my.log');
+ $log-&gt;message('Hello');
+ $this-&gt;assertTrue(file_exists('my.log'));
+ }</strong>
+}
+?&gt;
+</pre>
+ </p>
+ <p>
+ These tools are designed for the developer.
+ Tests are written in the PHP language itself more or less
+ as the application itself is built.
+ The advantage of using PHP itself as the testing language is that
+ there are no new languages to learn, testing can start straight away,
+ and the developer can test any part of the code.
+ Basically, all parts that can be accessed by the application code can also be
+ accessed by the test code, if they are in the same programming language.
+ </p>
+ <p>
+ The simplest type of test case is the
+ <a href="unit_tester_documentation.html">UnitTestCase</a>.
+ This class of test case includes standard tests for equality,
+ references and pattern matching.
+ All these test the typical expectations of what you would
+ expect the result of a function or method to be.
+ This is by far the most common type of test in the daily
+ routine of development, making up about 95% of test cases.
+ </p>
+ <p>
+ The top level task of a web application though is not to
+ produce correct output from its methods and objects, but
+ to generate web pages.
+ The <a href="web_tester_documentation.html">WebTestCase</a> class tests web
+ pages.
+ It simulates a web browser requesting a page, complete with
+ cookies, proxies, secure connections, authentication, forms, frames and most
+ navigation elements.
+ With this type of test case, the developer can assert that
+ information is present in the page and that forms and
+ sessions are handled correctly.
+ </p>
+ <p>
+ A <a href="web_tester_documentation.html">WebTestCase</a> looks like this...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');
+require_once('simpletest/web_tester.php');
+
+class <strong>MySiteTest</strong> extends WebTestCase {
+ <strong>
+ function testHomePage() {
+ $this-&gt;get('http://www.my-site.com/index.php');
+ $this-&gt;assertTitle('My Home Page');
+ $this-&gt;clickLink('Contact');
+ $this-&gt;assertTitle('Contact me');
+ $this-&gt;assertPattern('/Email me at/');
+ }</strong>
+}
+?&gt;
+</pre>
+ </p>
+
+ <p><a class="target" name="features"><h2>Feature list</h2></a></p>
+ <p>
+ The following is a very rough outline of past and future features
+ and their expected point of release.
+ I am afraid it is liable to change without warning, as meeting the
+ milestones rather depends on time available.
+ Green stuff has been coded, but not necessarily released yet.
+ If you have a pressing need for a green but unreleased feature
+ then you should check-out the code from Sourceforge SVN directly.
+ <table>
+<thead>
+ <tr>
+<th>Feature</th>
+<th>Description</th>
+<th>Release</th>
+</tr>
+ </thead>
+<tbody>
+<tr>
+ <td>Unit test case</td>
+ <td>Core test case class and assertions</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Html display</td>
+ <td>Simplest possible display</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Autoloading of test cases</td>
+ <td>
+ Reading a file with test cases and loading them into a
+ group test automatically
+ </td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Mock objects</td>
+ <td>
+ Objects capable of simulating other objects removing
+ test dependencies
+ </td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Web test case</td>
+ <td>Allows link following and title tag matching</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Partial mocks</td>
+ <td>
+ Mocking parts of a class for testing less than a class
+ or for complex simulations
+ </td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Web cookie handling</td>
+ <td>Correct handling of cookies when fetching pages</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Following redirects</td>
+ <td>Page fetching automatically follows 300 redirects</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Form parsing</td>
+ <td>Ability to submit simple forms and read default form values</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Command line interface</td>
+ <td>Test display without the need of a web browser</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Exposure of expectation classes</td>
+ <td>Can create precise tests with mocks as well as test cases</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>XML output and parsing</td>
+ <td>
+ Allows multi host testing and the integration of acceptance
+ testing extensions
+ </td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Browser component</td>
+ <td>
+ Exposure of lower level web browser interface for more
+ detailed test cases
+ </td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>HTTP authentication</td>
+ <td>
+ Fetching protected web pages with basic authentication
+ only
+ </td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>SSL support</td>
+ <td>Can connect to https: pages</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Proxy support</td>
+ <td>Can connect via. common proxies</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>Frames support</td>
+ <td>Handling of frames in web test cases</td>
+ <td style="color: green;">1.0</td>
+ </tr>
+ <tr>
+ <td>File upload testing</td>
+ <td>Can simulate the input type file tag</td>
+ <td style="color: green;">1.0.1</td>
+ </tr>
+ <tr>
+ <td>Mocking interfaces</td>
+ <td>
+ Can generate mock objects to interfaces as well as classes
+ and class interfaces are carried for type hints
+ </td>
+ <td style="color: green;">1.0.1</td>
+ </tr>
+ <tr>
+ <td>Testing exceptions</td>
+ <td>Similar to testing PHP errors</td>
+ <td style="color: green;">1.0.1</td>
+ </tr>
+ <tr>
+ <td>HTML label support</td>
+ <td>Can access all controls using the visual label</td>
+ <td style="color: green;">1.0.1</td>
+ </tr>
+ <tr>
+ <td>Base tag support</td>
+ <td>Respects page base tag when clicking</td>
+ <td style="color: green;">1.0.1</td>
+ </tr>
+ <tr>
+ <td>PHP 5 E_STRICT compliant</td>
+ <td>PHP 5 only version that works with the E_STRICT error level</td>
+ <td style="color: red;">1.1</td>
+ </tr>
+ <tr>
+ <td>BDD style fixtures</td>
+ <td>Can import fixtures using a mixin like given() method</td>
+ <td style="color: red;">1.5</td>
+ </tr>
+ <tr>
+ <td>Reporting machinery enhancements</td>
+ <td>Improved message passing for better cooperation with IDEs</td>
+ <td style="color: red;">1.5</td>
+ </tr>
+ <tr>
+ <td>Fluent mock interface</td>
+ <td>More flexible and concise mock objects</td>
+ <td style="color: red;">1.6</td>
+ </tr>
+ <tr>
+ <td>Localisation</td>
+ <td>Messages abstracted and code generated</td>
+ <td style="color: red;">1.6</td>
+ </tr>
+ <tr>
+ <td>CSS selectors</td>
+ <td>HTML content can be examined using CSS selectors</td>
+ <td style="color: red;">1.7</td>
+ </tr>
+ <tr>
+ <td>HTML table assertions</td>
+ <td>Can match HTML or table elements to expectations</td>
+ <td style="color: red;">1.7</td>
+ </tr>
+ <tr>
+ <td>Unified acceptance testing model</td>
+ <td>Content searchable through selectors combined with expectations</td>
+ <td style="color: red;">1.7</td>
+ </tr>
+ <tr>
+ <td>DatabaseTestCase</td>
+ <td>SQL selectors and DB drivers</td>
+ <td style="color: red;">1.7</td>
+ </tr>
+ <tr>
+ <td>IFrame support</td>
+ <td>Reads IFrame content that can be refreshed</td>
+ <td style="color: red;">1.8</td>
+ </tr>
+ <tr>
+ <td>Alternate HTML parsers</td>
+ <td>Can detect compiled parsers for performance improvements</td>
+ <td style="color: red;">1.8</td>
+ </tr>
+ <tr>
+ <td>Integrated Selenium support</td>
+ <td>Easy to use built in Selenium driver and tutorial</td>
+ <td style="color: red;">1.9</td>
+ </tr>
+ <tr>
+ <td>Code coverage</td>
+ <td>Reports using the bundled tool when using XDebug</td>
+ <td style="color: red;">1.9</td>
+ </tr>
+ <tr>
+ <td>Deprecation of old methods</td>
+ <td>Simpler interface for SimpleTest2</td>
+ <td style="color: red;">2.0</td>
+ </tr>
+ <tr>
+ <td>Javascript suport</td>
+ <td>Use of PECL module to add Javascript to the native browser</td>
+ <td style="color: red;">3.0</td>
+ </tr>
+ </tbody>
+</table>
+ PHP5 migraton will start straight after the version 1.0.1 series,
+ whereupon only PHP 5.1+ will be supported.
+ SimpleTest is currently compatible with PHP 5, but will not
+ make use of all of the new features until version 1.1.
+ </p>
+
+ <p><a class="target" name="resources"><h2>Web resources for testing</h2></a></p>
+ <p>
+ Process is at least as important as tools.
+ The type of process that makes the heaviest use of a developer's
+ testing tool is of course
+ <a href="http://www.extremeprogramming.org/">Extreme Programming</a>.
+ This is one of the
+ <a href="http://www.agilealliance.com/articles/index">Agile Methodologies</a>
+ which combine various practices to "flatten the cost curve" of software development.
+ More extreme still is <a href="http://www.testdriven.com/modules/news/">Test Driven Development</a>,
+ where you very strictly adhere to the rule of no coding until you have a test.
+ If you're more of a planner, or believe that experience trumps evolution,
+ you may prefer the
+ <a href="http://www.therationaledge.com/content/dec_01/f_spiritOfTheRUP_pk.html">RUP</a> approach.
+ I haven't tried it, but even I can see that you will need test tools (see figure 9).
+ </p>
+ <p>
+ Most unit testers clone <a href="http://www.junit.org/">JUnit</a> to some degree,
+ as far as the interface at least. There is a wealth of information on the
+ JUnit site including the
+ <a href="http://junit.sourceforge.net/doc/faq/faq.htm">FAQ</a>
+ which contains plenty of general advice on testing.
+ Once you get bitten by the bug you will certainly appreciate the phrase
+ <a href="http://junit.sourceforge.net/doc/testinfected/testing.htm">test infected</a>
+ coined by Eric Gamma.
+ If you are still reviewing which unit tester to use you can find pretty complete
+ lists from
+ <a href="http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks">Wikipedia</a>,
+ <a href="http://www.testingfaqs.org/t-unit.html">Software testing FAQ</a>,
+ and <a href="http://www.opensourcetesting.org/functional.php">Open source testing</a>.
+ </p>
+ <p>
+ There is still very little material on using mock objects, which is a shame
+ as unit testing without them is a lot more work.
+ The <a href="http://www.sidewize.com/company/mockobjects.pdf">original mock objects paper</a>
+ is very Java focused, but still worth a read.
+ The most authoritive sources are probably
+ <a href="http://mockobjects.com">the original mock objects site</a> and
+ <a href="http://jmock.org/">JMock</a>.
+ Java centric, but tucked away in PDFs they contain some deep knowledge on using mocks from the
+ extended experience of the concept inventors.
+ As a new technology there are plenty of discussions and debate on how to use mocks,
+ often on Wikis such as
+ <a href="http://xpdeveloper.com/cgi-bin/oldwiki.cgi?MockObjects">Extreme Tuesday</a>
+ or <a href="http://www.mockobjects.com/MocksObjectsPaper.html">www.mockobjects.com</a>
+ or <a href="http://c2.com/cgi/wiki?MockObject">the original C2 Wiki</a>.
+ Injecting mocks into a class is the main area of debate for which this
+ <a href="http://www-106.ibm.com/developerworks/java/library/j-mocktest.html">paper on IBM</a>
+ makes a good starting point.
+ </p>
+ <p>
+ There are plenty of web testing tools, but the scriptable ones
+ are mostly are written in Java and
+ tutorials and advice are rather thin on the ground.
+ The only hope is to look at the documentation for
+ <a href="http://httpunit.sourceforge.net/">HTTPUnit</a>,
+ <a href="http://htmlunit.sourceforge.net/">HTMLUnit</a>
+ or <a href="http://jwebunit.sourceforge.net/">JWebUnit</a> and hope for clues.
+ There are some XML driven test frameworks, but again most
+ require Java to run.
+ </p>
+ <p>
+ Most significant is a new generation of tools that run directly in the web browser
+ are now available.
+ These include
+ <a href="http://www.openqa.org/selenium/">Selenium</a> and
+ <a href="http://wtr.rubyforge.org/">Watir</a>.
+ They are non-trivial to set up and slow to run, but can essentially test anything.
+ As SimpleTest does not support JavaScript you would probably
+ have to look at these tools anyway if you have highly dynamic
+ pages.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ <a href="unit_test_documentation.html">Documentation for SimpleTest</a>.
+ </li>
+<li>
+ <a href="http://www.lastcraft.com/first_test_tutorial.php">How to write PHP test cases</a>
+ is a fairly advanced tutorial.
+ </li>
+<li>
+ <a href="http://simpletest.org/api/">SimpleTest API</a> from phpdoc.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <span class="chosen">Overview</span>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/partial_mocks_documentation.html b/vendors/simpletest/docs/en/partial_mocks_documentation.html
new file mode 100644
index 000000000..4cae18c9d
--- /dev/null
+++ b/vendors/simpletest/docs/en/partial_mocks_documentation.html
@@ -0,0 +1,445 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest for PHP partial mocks documentation</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <span class="chosen">Partial mocks</span>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Partial mock objects documentation</h1>
+ This page...
+ <ul>
+<li>
+ <a href="#inject">The mock injection problem</a>.
+ </li>
+<li>
+ Moving creation to a <a href="#creation">protected factory</a> method.
+ </li>
+<li>
+ <a href="#partial">Partial mocks</a> generate subclasses.
+ </li>
+<li>
+ Partial mocks <a href="#less">test less than a class</a>.
+ </li>
+</ul>
+<div class="content">
+
+ <p>
+ A partial mock is simply a pattern to alleviate a specific problem
+ in testing with mock objects,
+ that of getting mock objects into tight corners.
+ It's quite a limited tool and possibly not even a good idea.
+ It is included with SimpleTest because I have found it useful
+ on more than one occasion and has saved a lot of work at that point.
+ </p>
+
+ <p><a class="target" name="inject"><h2>The mock injection problem</h2></a></p>
+ <p>
+ When one object uses another it is very simple to just pass a mock
+ version in already set up with its expectations.
+ Things are rather tricker if one object creates another and the
+ creator is the one you want to test.
+ This means that the created object should be mocked, but we can
+ hardly tell our class under test to create a mock instead.
+ The tested class doesn't even know it is running inside a test
+ after all.
+ </p>
+ <p>
+ For example, suppose we are building a telnet client and it
+ needs to create a network socket to pass its messages.
+ The connection method might look something like...
+<pre>
+<strong>&lt;?php
+require_once('socket.php');
+
+class Telnet {
+ ...
+ function &amp;connect($ip, $port, $username, $password) {
+ $socket = &amp;new Socket($ip, $port);
+ $socket-&gt;read( ... );
+ ...
+ }
+}
+?&gt;</strong>
+</pre>
+ We would really like to have a mock object version of the socket
+ here, what can we do?
+ </p>
+ <p>
+ The first solution is to pass the socket in as a parameter,
+ forcing the creation up a level.
+ Having the client handle this is actually a very good approach
+ if you can manage it and should lead to factoring the creation from
+ the doing.
+ In fact, this is one way in which testing with mock objects actually
+ forces you to code more tightly focused solutions.
+ They improve your programming.
+ </p>
+ <p>
+ Here this would be...
+<pre>
+&lt;?php
+require_once('socket.php');
+
+class Telnet {
+ ...
+ <strong>function &amp;connect(&amp;$socket, $username, $password) {
+ $socket-&gt;read( ... );
+ ...
+ }</strong>
+}
+?&gt;
+</pre>
+ This means that the test code is typical for a test involving
+ mock objects.
+<pre>
+class TelnetTest extends UnitTestCase {
+ ...
+ function testConnection() {<strong>
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new Telnet();
+ $telnet-&gt;connect($socket, 'Me', 'Secret');
+ ...</strong>
+ }
+}
+</pre>
+ It is pretty obvious though that one level is all you can go.
+ You would hardly want your top level application creating
+ every low level file, socket and database connection ever
+ needed.
+ It wouldn't know the constructor parameters anyway.
+ </p>
+ <p>
+ The next simplest compromise is to have the created object passed
+ in as an optional parameter...
+<pre>
+&lt;?php
+require_once('socket.php');
+
+class Telnet {
+ ...<strong>
+ function &amp;connect($ip, $port, $username, $password, $socket = false) {
+ if (!$socket) {
+ $socket = &amp;new Socket($ip, $port);
+ }
+ $socket-&gt;read( ... );</strong>
+ ...
+ return $socket;
+ }
+}
+?&gt;
+</pre>
+ For a quick solution this is usually good enough.
+ The test now looks almost the same as if the parameter
+ was formally passed...
+<pre>
+class TelnetTest extends UnitTestCase {
+ ...
+ function testConnection() {<strong>
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new Telnet();
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret', &amp;$socket);
+ ...</strong>
+ }
+}
+</pre>
+ The problem with this approach is its untidiness.
+ There is test code in the main class and parameters passed
+ in the test case that are never used.
+ This is a quick and dirty approach, but nevertheless effective
+ in most situations.
+ </p>
+ <p>
+ The next method is to pass in a factory object to do the creation...
+<pre>
+&lt;?php
+require_once('socket.php');
+
+class Telnet {<strong>
+ function Telnet(&amp;$network) {
+ $this-&gt;_network = &amp;$network;
+ }</strong>
+ ...
+ function &amp;connect($ip, $port, $username, $password) {<strong>
+ $socket = &amp;$this-&gt;_network-&gt;createSocket($ip, $port);
+ $socket-&gt;read( ... );</strong>
+ ...
+ return $socket;
+ }
+}
+?&gt;
+</pre>
+ This is probably the most highly factored answer as creation
+ is now moved into a small specialist class.
+ The networking factory can now be tested separately, but mocked
+ easily when we are testing the telnet class...
+<pre>
+class TelnetTest extends UnitTestCase {
+ ...
+ function testConnection() {<strong>
+ $socket = &amp;new MockSocket($this);
+ ...
+ $network = &amp;new MockNetwork($this);
+ $network-&gt;setReturnReference('createSocket', $socket);
+ $telnet = &amp;new Telnet($network);
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
+ ...</strong>
+ }
+}
+</pre>
+ The downside is that we are adding a lot more classes to the
+ library.
+ Also we are passing a lot of factories around which will
+ make the code a little less intuitive.
+ The most flexible solution, but the most complex.
+ </p>
+ <p>
+ Is there a middle ground?
+ </p>
+
+ <p><a class="target" name="creation"><h2>Protected factory method</h2></a></p>
+ <p>
+ There is a way we can circumvent the problem without creating
+ any new application classes, but it involves creating a subclass
+ when we do the actual testing.
+ Firstly we move the socket creation into its own method...
+<pre>
+&lt;?php
+require_once('socket.php');
+
+class Telnet {
+ ...
+ function &amp;connect($ip, $port, $username, $password) {<strong>
+ $socket = &amp;$this-&gt;_createSocket($ip, $port);</strong>
+ $socket-&gt;read( ... );
+ ...
+ }<strong>
+
+ function &amp;_createSocket($ip, $port) {
+ return new Socket($ip, $port);
+ }</strong>
+}
+?&gt;
+</pre>
+ This is the only change we make to the application code.
+ </p>
+ <p>
+ For the test case we have to create a subclass so that
+ we can intercept the socket creation...
+<pre>
+<strong>class TelnetTestVersion extends Telnet {
+ var $_mock;
+
+ function TelnetTestVersion(&amp;$mock) {
+ $this-&gt;_mock = &amp;$mock;
+ $this-&gt;Telnet();
+ }
+
+ function &amp;_createSocket() {
+ return $this-&gt;_mock;
+ }
+}</strong>
+</pre>
+ Here I have passed the mock in the constructor, but a
+ setter would have done just as well.
+ Note that the mock was set into the object variable
+ before the constructor was chained.
+ This is necessary in case the constructor calls
+ <span class="new_code">connect()</span>.
+ Otherwise it could get a null value from
+ <span class="new_code">_createSocket()</span>.
+ </p>
+ <p>
+ After the completion of all of this extra work the
+ actual test case is fairly easy.
+ We just test our new class instead...
+<pre>
+class TelnetTest extends UnitTestCase {
+ ...
+ function testConnection() {<strong>
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new TelnetTestVersion($socket);
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
+ ...</strong>
+ }
+}
+</pre>
+ The new class is very simple of course.
+ It just sets up a return value, rather like a mock.
+ It would be nice if it also checked the incoming parameters
+ as well.
+ Just like a mock.
+ It seems we are likely to do this often, can
+ we automate the subclass creation?
+ </p>
+
+ <p><a class="target" name="partial"><h2>A partial mock</h2></a></p>
+ <p>
+ Of course the answer is "yes" or I would have stopped writing
+ this by now!
+ The previous test case was a lot of work, but we can
+ generate the subclass using a similar approach to the mock objects.
+ </p>
+ <p>
+ Here is the partial mock version of the test...
+<pre>
+<strong>Mock::generatePartial(
+ 'Telnet',
+ 'TelnetTestVersion',
+ array('_createSocket'));</strong>
+
+class TelnetTest extends UnitTestCase {
+ ...
+ function testConnection() {<strong>
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new TelnetTestVersion($this);
+ $telnet-&gt;setReturnReference('_createSocket', $socket);
+ $telnet-&gt;Telnet();
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
+ ...</strong>
+ }
+}
+</pre>
+ The partial mock is a subclass of the original with
+ selected methods "knocked out" with test
+ versions.
+ The <span class="new_code">generatePartial()</span> call
+ takes three parameters: the class to be subclassed,
+ the new test class name and a list of methods to mock.
+ </p>
+ <p>
+ Instantiating the resulting objects is slightly tricky.
+ The only constructor parameter of a partial mock is
+ the unit tester reference.
+ As with the normal mock objects this is needed for sending
+ test results in response to checked expectations.
+ </p>
+ <p>
+ The original constructor is not run yet.
+ This is necessary in case the constructor is going to
+ make use of the as yet unset mocked methods.
+ We set any return values at this point and then run the
+ constructor with its normal parameters.
+ This three step construction of "new", followed
+ by setting up the methods, followed by running the constructor
+ proper is what distinguishes the partial mock code.
+ </p>
+ <p>
+ Apart from construction, all of the mocked methods have
+ the same features as mock objects and all of the unmocked
+ methods behave as before.
+ We can set expectations very easily...
+<pre>
+class TelnetTest extends UnitTestCase {
+ ...
+ function testConnection() {
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new TelnetTestVersion($this);
+ $telnet-&gt;setReturnReference('_createSocket', $socket);<strong>
+ $telnet-&gt;expectOnce('_createSocket', array('127.0.0.1', 21));</strong>
+ $telnet-&gt;Telnet();
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
+ ...<strong>
+ $telnet-&gt;tally();</strong>
+ }
+}
+</pre>
+ </p>
+
+ <p><a class="target" name="less"><h2>Testing less than a class</h2></a></p>
+ <p>
+ The mocked out methods don't have to be factory methods,
+ they could be any sort of method.
+ In this way partial mocks allow us to take control of any part of
+ a class except the constructor.
+ We could even go as far as to mock every method
+ except one we actually want to test.
+ </p>
+ <p>
+ This last situation is all rather hypothetical, as I haven't
+ tried it.
+ I am open to the possibility, but a little worried that
+ forcing object granularity may be better for the code quality.
+ I personally use partial mocks as a way of overriding creation
+ or for occasional testing of the TemplateMethod pattern.
+ </p>
+ <p>
+ It's all going to come down to the coding standards of your
+ project to decide which mechanism you use.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ <a href="http://simpletest.org/api/">Full API for SimpleTest</a>
+ from the PHPDoc.
+ </li>
+<li>
+ The protected factory is described in
+ <a href="http://www-106.ibm.com/developerworks/java/library/j-mocktest.html">this paper from IBM</a>.
+ This is the only formal comment I have seen on this problem.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <span class="chosen">Partial mocks</span>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/reporter_documentation.html b/vendors/simpletest/docs/en/reporter_documentation.html
new file mode 100644
index 000000000..87c89e44b
--- /dev/null
+++ b/vendors/simpletest/docs/en/reporter_documentation.html
@@ -0,0 +1,519 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest for PHP test runner and display documentation</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <span class="chosen">Reporting</span>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Test reporter documentation</h1>
+ This page...
+ <ul>
+<li>
+ Displaying <a href="#html">results in HTML</a>
+ </li>
+<li>
+ Displaying and <a href="#other">reporting results</a>
+ in other formats
+ </li>
+<li>
+ Using <a href="#cli">SimpleTest from the command line</a>
+ </li>
+<li>
+ Using <a href="#xml">Using XML</a> for remote testing
+ </li>
+</ul>
+<div class="content">
+
+ <p>
+ SimpleTest pretty much follows the MVC pattern
+ (Model-View-Controller).
+ The reporter classes are the view and the model is your
+ test cases and their hiearchy.
+ The controller is mostly hidden from the user of
+ SimpleTest unless you want to change how the test cases
+ are actually run, in which case it is possible to
+ override the runner objects from within the test case.
+ As usual with MVC, the controller is mostly undefined
+ and there are other places to control the test run.
+ </p>
+
+ <p><a class="target" name="html"><h2>Reporting results in HTML</h2></a></p>
+ <p>
+ The default test display is minimal in the extreme.
+ It reports success and failure with the conventional red and
+ green bars and shows a breadcrumb trail of test groups
+ for every failed assertion.
+ Here's a fail...
+ <div class="demo">
+ <h1>File test</h1>
+ <span class="fail">Fail</span>: createnewfile-&gt;True assertion failed.<br>
+ <div style="padding: 8px; margin-top: 1em; background-color: red; color: white;">1/1 test cases complete.
+ <strong>0</strong> passes, <strong>1</strong> fails and <strong>0</strong> exceptions.</div>
+ </div>
+ And here all tests passed...
+ <div class="demo">
+ <h1>File test</h1>
+ <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
+ <strong>1</strong> passes, <strong>0</strong> fails and <strong>0</strong> exceptions.</div>
+ </div>
+ The good news is that there are several points in the display
+ hiearchy for subclassing.
+ </p>
+ <p>
+ For web page based displays there is the
+ <span class="new_code">HtmlReporter</span> class with the following
+ signature...
+<pre>
+class HtmlReporter extends SimpleReporter {
+ public HtmlReporter($encoding) { ... }
+ public makeDry(boolean $is_dry) { ... }
+ public void paintHeader(string $test_name) { ... }
+ public void sendNoCacheHeaders() { ... }
+ public void paintFooter(string $test_name) { ... }
+ public void paintGroupStart(string $test_name, integer $size) { ... }
+ public void paintGroupEnd(string $test_name) { ... }
+ public void paintCaseStart(string $test_name) { ... }
+ public void paintCaseEnd(string $test_name) { ... }
+ public void paintMethodStart(string $test_name) { ... }
+ public void paintMethodEnd(string $test_name) { ... }
+ public void paintFail(string $message) { ... }
+ public void paintPass(string $message) { ... }
+ public void paintError(string $message) { ... }
+ public void paintException(string $message) { ... }
+ public void paintMessage(string $message) { ... }
+ public void paintFormattedMessage(string $message) { ... }
+ protected string _getCss() { ... }
+ public array getTestList() { ... }
+ public integer getPassCount() { ... }
+ public integer getFailCount() { ... }
+ public integer getExceptionCount() { ... }
+ public integer getTestCaseCount() { ... }
+ public integer getTestCaseProgress() { ... }
+}
+</pre>
+ Here is what some of these methods mean. First the display methods
+ that you will probably want to override...
+ <ul class="api">
+ <li>
+ <span class="new_code">HtmlReporter(string $encoding)</span><br>
+ is the constructor.
+ Note that the unit test sets up the link to the display
+ rather than the other way around.
+ The display is a mostly passive receiver of test events.
+ This allows easy adaption of the display for other test
+ systems beside unit tests, such as monitoring servers.
+ The encoding is the character encoding you wish to
+ display the test output in.
+ In order to correctly render debug output when
+ using the web tester, this should match the encoding
+ of the site you are trying to test.
+ The available character set strings are described in
+ the PHP <a href="http://www.php.net/manual/en/function.htmlentities.php">html_entities()</a>
+ function.
+ </li>
+ <li>
+ <span class="new_code">void paintHeader(string $test_name)</span><br>
+ is called once at the very start of the test when the first
+ start event arrives.
+ The first start event is usually delivered by the top level group
+ test and so this is where <span class="new_code">$test_name</span>
+ comes from.
+ It paints the page titles, CSS, body tag, etc.
+ It returns nothing (<span class="new_code">void</span>).
+ </li>
+ <li>
+ <span class="new_code">void paintFooter(string $test_name)</span><br>
+ Called at the very end of the test to close any tags opened
+ by the page header.
+ By default it also displays the red/green bar and the final
+ count of results.
+ Actually the end of the test happens when a test end event
+ comes in with the same name as the one that started it all
+ at the same level.
+ The tests nest you see.
+ Closing the last test finishes the display.
+ </li>
+ <li>
+ <span class="new_code">void paintMethodStart(string $test_name)</span><br>
+ is called at the start of each test method.
+ The name normally comes from method name.
+ The other test start events behave the same way except
+ that the group test one tells the reporter how large
+ it is in number of held test cases.
+ This is so that the reporter can display a progress bar
+ as the runner churns through the test cases.
+ </li>
+ <li>
+ <span class="new_code">void paintMethodEnd(string $test_name)</span><br>
+ backs out of the test started with the same name.
+ </li>
+ <li>
+ <span class="new_code">void paintFail(string $message)</span><br>
+ paints a failure.
+ By default it just displays the word fail, a breadcrumbs trail
+ showing the current test nesting and the message issued by
+ the assertion.
+ </li>
+ <li>
+ <span class="new_code">void paintPass(string $message)</span><br>
+ by default does nothing.
+ </li>
+ <li>
+ <span class="new_code">string _getCss()</span><br>
+ Returns the CSS styles as a string for the page header
+ method.
+ Additional styles have to be appended here if you are
+ not overriding the page header.
+ You will want to use this method in an overriden page header
+ if you want to include the original CSS.
+ </li>
+ </ul>
+ There are also some accessors to get information on the current
+ state of the test suite.
+ Use these to enrich the display...
+ <ul class="api">
+ <li>
+ <span class="new_code">array getTestList()</span><br>
+ is the first convenience method for subclasses.
+ Lists the current nesting of the tests as a list
+ of test names.
+ The first, most deeply nested test, is first in the
+ list and the current test method will be last.
+ </li>
+ <li>
+ <span class="new_code">integer getPassCount()</span><br>
+ returns the number of passes chalked up so far.
+ Needed for the display at the end.
+ </li>
+ <li>
+ <span class="new_code">integer getFailCount()</span><br>
+ is likewise the number of fails so far.
+ </li>
+ <li>
+ <span class="new_code">integer getExceptionCount()</span><br>
+ is likewise the number of errors so far.
+ </li>
+ <li>
+ <span class="new_code">integer getTestCaseCount()</span><br>
+ is the total number of test cases in the test run.
+ This includes the grouping tests themselves.
+ </li>
+ <li>
+ <span class="new_code">integer getTestCaseProgress()</span><br>
+ is the number of test cases completed so far.
+ </li>
+ </ul>
+ One simple modification is to get the HtmlReporter to display
+ the passes as well as the failures and errors...
+<pre>
+<strong>class ShowPasses extends HtmlReporter {
+
+ function paintPass($message) {
+ parent::paintPass($message);
+ print "&amp;&lt;span class=\"pass\"&gt;Pass&lt;/span&gt;: ";
+ $breadcrumb = $this-&gt;getTestList();
+ array_shift($breadcrumb);
+ print implode("-&amp;gt;", $breadcrumb);
+ print "-&amp;gt;$message&lt;br /&gt;\n";
+ }
+
+ function _getCss() {
+ return parent::_getCss() . ' .pass { color: green; }';
+ }
+}</strong>
+</pre>
+ </p>
+ <p>
+ One method that was glossed over was the <span class="new_code">makeDry()</span>
+ method.
+ If you run this method, with no parameters, on the reporter
+ before the test suite is run no actual test methods
+ will be called.
+ You will still get the events of entering and leaving the
+ test methods and test cases, but no passes or failures etc,
+ because the test code will not actually be executed.
+ </p>
+ <p>
+ The reason for this is to allow for more sophistcated
+ GUI displays that allow the selection of individual test
+ cases.
+ In order to build a list of possible tests they need a
+ report on the test structure for drawing, say a tree view
+ of the test suite.
+ With a reporter set to dry run that just sends drawing events
+ this is easily accomplished.
+ </p>
+
+ <p><a class="target" name="other"><h2>Extending the reporter</h2></a></p>
+ <p>
+ Rather than simply modifying the existing display, you might want to
+ produce a whole new HTML look, or even generate text or XML.
+ Rather than override every method in
+ <span class="new_code">HtmlReporter</span> we can take one
+ step up the class hiearchy to <span class="new_code">SimpleReporter</span>
+ in the <em>simple_test.php</em> source file.
+ </p>
+ <p>
+ A do nothing display, a blank canvas for your own creation, would
+ be...
+<pre>
+<strong>require_once('simpletest/simple_test.php');</strong>
+
+class MyDisplay extends SimpleReporter {<strong>
+ </strong>
+ function paintHeader($test_name) {
+ }
+
+ function paintFooter($test_name) {
+ }
+
+ function paintStart($test_name, $size) {<strong>
+ parent::paintStart($test_name, $size);</strong>
+ }
+
+ function paintEnd($test_name, $size) {<strong>
+ parent::paintEnd($test_name, $size);</strong>
+ }
+
+ function paintPass($message) {<strong>
+ parent::paintPass($message);</strong>
+ }
+
+ function paintFail($message) {<strong>
+ parent::paintFail($message);</strong>
+ }
+}
+</pre>
+ No output would come from this class until you add it.
+ </p>
+
+ <p><a class="target" name="cli"><h2>The command line reporter</h2></a></p>
+ <p>
+ SimpleTest also ships with a minimal command line reporter.
+ The interface mimics JUnit to some extent, but paints the
+ failure messages as they arrive.
+ To use the command line reporter simply substitute it
+ for the HTML version...
+<pre>
+&lt;?php
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/reporter.php');
+
+$test = &amp;new TestSuite('File test');
+$test-&gt;addTestFile('tests/file_test.php');
+$test-&gt;run(<strong>new TextReporter()</strong>);
+?&gt;
+</pre>
+ Then invoke the test suite from the command line...
+<pre class="shell">
+php file_test.php
+</pre>
+ You will need the command line version of PHP installed
+ of course.
+ A passing test suite looks like this...
+<pre class="shell">
+File test
+OK
+Test cases run: 1/1, Failures: 0, Exceptions: 0
+</pre>
+ A failure triggers a display like this...
+<pre class="shell">
+File test
+1) True assertion failed.
+ in createnewfile
+FAILURES!!!
+Test cases run: 1/1, Failures: 1, Exceptions: 0
+</pre>
+ </p>
+ <p>
+ One of the main reasons for using a command line driven
+ test suite is of using the tester as part of some automated
+ process.
+ To function properly in shell scripts the test script should
+ return a non-zero exit code on failure.
+ If a test suite fails the value <span class="new_code">false</span>
+ is returned from the <span class="new_code">SimpleTest::run()</span>
+ method.
+ We can use that result to exit the script with the desired return
+ code...
+<pre>
+&lt;?php
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/reporter.php');
+
+$test = &amp;new TestSuite('File test');
+$test-&gt;addTestFile('tests/file_test.php');
+<strong>exit ($test-&gt;run(new TextReporter()) ? 0 : 1);</strong>
+?&gt;
+</pre>
+ Of course we don't really want to create two test scripts,
+ a command line one and a web browser one, for each test suite.
+ The command line reporter includes a method to sniff out the
+ run time environment...
+<pre>
+&lt;?php
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/reporter.php');
+
+$test = &amp;new TestSuite('File test');
+$test-&gt;addTestFile('tests/file_test.php');
+<strong>if (TextReporter::inCli()) {</strong>
+ exit ($test-&gt;run(new TextReporter()) ? 0 : 1);
+<strong>}</strong>
+$test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ This is the form used within SimpleTest itself.
+ </p>
+
+ <p><a class="target" name="xml"><h2>Remote testing</h2></a></p>
+ <p>
+ SimpleTest ships with an <span class="new_code">XmlReporter</span> class
+ used for internal communication.
+ When run the output looks like...
+<pre class="shell">
+&lt;?xml version="1.0"?&gt;
+&lt;run&gt;
+ &lt;group size="4"&gt;
+ &lt;name&gt;Remote tests&lt;/name&gt;
+ &lt;group size="4"&gt;
+ &lt;name&gt;Visual test with 48 passes, 48 fails and 4 exceptions&lt;/name&gt;
+ &lt;case&gt;
+ &lt;name&gt;testofunittestcaseoutput&lt;/name&gt;
+ &lt;test&gt;
+ &lt;name&gt;testofresults&lt;/name&gt;
+ &lt;pass&gt;This assertion passed&lt;/pass&gt;
+ &lt;fail&gt;This assertion failed&lt;/fail&gt;
+ &lt;/test&gt;
+ &lt;test&gt;
+ ...
+ &lt;/test&gt;
+ &lt;/case&gt;
+ &lt;/group&gt;
+ &lt;/group&gt;
+&lt;/run&gt;
+</pre>
+ You can make use of this format with the parser
+ supplied as part of SimpleTest itself.
+ This is called <span class="new_code">SimpleTestXmlParser</span> and
+ resides in <em>xml.php</em> within the SimpleTest package...
+<pre>
+&lt;?php
+require_once('simpletest/xml.php');
+
+...
+$parser = &amp;new SimpleTestXmlParser(new HtmlReporter());
+$parser-&gt;parse($test_output);
+?&gt;
+</pre>
+ The <span class="new_code">$test_output</span> should be the XML format
+ from the XML reporter, and could come from say a command
+ line run of a test case.
+ The parser sends events to the reporter just like any
+ other test run.
+ There are some odd occasions where this is actually useful.
+ </p>
+ <p>
+ A problem with large test suites is thet they can exhaust
+ the default 8Mb memory limit on a PHP process.
+ By having the test groups output in XML and run in
+ separate processes, the output can be reparsed to
+ aggregate the results into a much smaller footprint top level
+ test.
+ </p>
+ <p>
+ Because the XML output can come from anywhere, this opens
+ up the possibility of aggregating test runs from remote
+ servers.
+ A test case already exists to do this within the SimpleTest
+ framework, but it is currently experimental...
+<pre>
+&lt;?php
+<strong>require_once('../remote.php');</strong>
+require_once('../reporter.php');
+
+$test_url = ...;
+$dry_url = ...;
+
+$test = &amp;new TestSuite('Remote tests');
+$test-&gt;addTestCase(<strong>new RemoteTestCase($test_url, $dry_url)</strong>);
+$test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ The <span class="new_code">RemoteTestCase</span> takes the actual location
+ of the test runner, basically a web page in XML format.
+ It also takes the URL of a reporter set to do a dry run.
+ This is so that progress can be reported upward correctly.
+ The <span class="new_code">RemoteTestCase</span> can be added to test suites
+ just like any other group test.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
+ gives full detail on the classes and assertions available.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <span class="chosen">Reporting</span>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/unit_test_documentation.html b/vendors/simpletest/docs/en/unit_test_documentation.html
new file mode 100644
index 000000000..bc43c82cc
--- /dev/null
+++ b/vendors/simpletest/docs/en/unit_test_documentation.html
@@ -0,0 +1,431 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest for PHP regression test documentation</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <span class="chosen">Unit tester</span>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>PHP Unit Test documentation</h1>
+ This page...
+ <ul>
+<li>
+ <a href="#unit">Unit test cases</a> and basic assertions.
+ </li>
+<li>
+ <a href="#extending_unit">Extending test cases</a> to
+ customise them for your own project.
+ </li>
+<li>
+ <a href="#running_unit">Running a single case</a> as
+ a single script.
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="unit"><h2>Unit test cases</h2></a></p>
+ <p>
+ The core system is a regression testing framework built around
+ test cases.
+ A sample test case looks like this...
+<pre>
+<strong>class FileTestCase extends UnitTestCase {
+}</strong>
+</pre>
+ Actual tests are added as methods in the test case whose names
+ by default start with the string "test" and
+ when the test case is invoked all such methods are run in
+ the order that PHP introspection finds them.
+ As many test methods can be added as needed.
+ </p>
+ <p>
+ For example...
+<pre>
+require_once('simpletest/autorun.php');
+require_once('../classes/writer.php');
+
+class FileTestCase extends UnitTestCase {
+ function FileTestCase() {
+ $this-&gt;UnitTestCase('File test');
+ }<strong>
+
+ function setUp() {
+ @unlink('../temp/test.txt');
+ }
+
+ function tearDown() {
+ @unlink('../temp/test.txt');
+ }
+
+ function testCreation() {
+ $writer = &amp;new FileWriter('../temp/test.txt');
+ $writer-&gt;write('Hello');
+ $this-&gt;assertTrue(file_exists('../temp/test.txt'), 'File created');
+ }</strong>
+}
+</pre>
+ The constructor is optional and usually omitted.
+ Without a name, the class name is taken as the name of the test case.
+ </p>
+ <p>
+ Our only test method at the moment is <span class="new_code">testCreation()</span>
+ where we check that a file has been created by our
+ <span class="new_code">Writer</span> object.
+ We could have put the <span class="new_code">unlink()</span>
+ code into this method as well, but by placing it in
+ <span class="new_code">setUp()</span> and
+ <span class="new_code">tearDown()</span> we can use it with
+ other test methods that we add.
+ </p>
+ <p>
+ The <span class="new_code">setUp()</span> method is run
+ just before each and every test method.
+ <span class="new_code">tearDown()</span> is run just after
+ each and every test method.
+ </p>
+ <p>
+ You can place some test case set up into the constructor to
+ be run once for all the methods in the test case, but
+ you risk test inteference that way.
+ This way is slightly slower, but it is safer.
+ Note that if you come from a JUnit background this will not
+ be the behaviour you are used to.
+ JUnit surprisingly reinstantiates the test case for each test
+ method to prevent such interference.
+ SimpleTest requires the end user to use <span class="new_code">setUp()</span>, but
+ supplies additional hooks for library writers.
+ </p>
+ <p>
+ The means of reporting test results (see below) are by a
+ visiting display class
+ that is notified by various <span class="new_code">assert...()</span>
+ methods.
+ Here is the full list for the <span class="new_code">UnitTestCase</span>
+ class, the default for SimpleTest...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">assertTrue($x)</span></td>
+<td>Fail if $x is false</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertFalse($x)</span></td>
+<td>Fail if $x is true</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNull($x)</span></td>
+<td>Fail if $x is set</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNotNull($x)</span></td>
+<td>Fail if $x not set</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertIsA($x, $t)</span></td>
+<td>Fail if $x is not the class or type $t</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNotA($x, $t)</span></td>
+<td>Fail if $x is of the class or type $t</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertEqual($x, $y)</span></td>
+<td>Fail if $x == $y is false</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNotEqual($x, $y)</span></td>
+<td>Fail if $x == $y is true</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertWithinMargin($x, $y, $m)</span></td>
+<td>Fail if abs($x - $y) &lt; $m is false</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertOutsideMargin($x, $y, $m)</span></td>
+<td>Fail if abs($x - $y) &lt; $m is true</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertIdentical($x, $y)</span></td>
+<td>Fail if $x == $y is false or a type mismatch</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNotIdentical($x, $y)</span></td>
+<td>Fail if $x == $y is true and types match</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertReference($x, $y)</span></td>
+<td>Fail unless $x and $y are the same variable</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertClone($x, $y)</span></td>
+<td>Fail unless $x and $y are identical copies</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertPattern($p, $x)</span></td>
+<td>Fail unless the regex $p matches $x</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoPattern($p, $x)</span></td>
+<td>Fail if the regex $p matches $x</td>
+</tr>
+ <tr>
+<td><span class="new_code">expectError($x)</span></td>
+<td>Swallows any upcoming matching error</td>
+</tr>
+ <tr>
+<td><span class="new_code">assert($e)</span></td>
+<td>Fail on failed <a href="expectation_documentation.html">expectation</a> object $e</td>
+</tr>
+ </tbody></table>
+ All assertion methods can take an optional description as a
+ last parameter.
+ This is to label the displayed result with.
+ If omitted a default message is sent instead, which is usually
+ sufficient.
+ This default message can still be embedded in your own message
+ if you include "%s" within the string.
+ All the assertions return true on a pass or false on failure.
+ </p>
+ <p>
+ Some examples...
+<pre>
+$variable = null;
+<strong>$this-&gt;assertNull($variable, 'Should be cleared');</strong>
+</pre>
+ ...will pass and normally show no message.
+ If you have
+ <a href="http://www.lastcraft.com/display_subclass_tutorial.php">set up the tester to display passes</a>
+ as well then the message will be displayed as is.
+<pre>
+<strong>$this-&gt;assertIdentical(0, false, 'Zero is not false [%s]');</strong>
+</pre>
+ This will fail as it performs a type
+ check, as well as a comparison, between the two values.
+ The "%s" part is replaced by the default
+ error message that would have been shown if we had not
+ supplied our own.
+<pre>
+$a = 1;
+$b = $a;
+<strong>$this-&gt;assertReference($a, $b);</strong>
+</pre>
+ Will fail as the variable <span class="new_code">$a</span> is a copy of <span class="new_code">$b</span>.
+<pre>
+<strong>$this-&gt;assertPattern('/hello/i', 'Hello world');</strong>
+</pre>
+ This will pass as using a case insensitive match the string
+ <span class="new_code">hello</span> is contained in <span class="new_code">Hello world</span>.
+<pre>
+<strong>$this-&gt;expectError();</strong>
+trigger_error('Catastrophe');
+</pre>
+ Here the check catches the "Catastrophe"
+ message without checking the text and passes.
+ This removes the error from the queue.
+<pre>
+<strong>$this-&gt;expectError('Catastrophe');</strong>
+trigger_error('Catastrophe');
+</pre>
+ The next error check tests not only the existence of the error,
+ but also the text which, here matches so another pass.
+ If any unchecked errors are left at the end of a test method then
+ an exception will be reported in the test.
+ </p>
+ <p>
+ Note that SimpleTest cannot catch compile time PHP errors.
+ </p>
+ <p>
+ The test cases also have some convenience methods for debugging
+ code or extending the suite...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">setUp()</span></td>
+<td>Runs this before each test method</td>
+</tr>
+ <tr>
+<td><span class="new_code">tearDown()</span></td>
+<td>Runs this after each test method</td>
+</tr>
+ <tr>
+<td><span class="new_code">pass()</span></td>
+<td>Sends a test pass</td>
+</tr>
+ <tr>
+<td><span class="new_code">fail()</span></td>
+<td>Sends a test failure</td>
+</tr>
+ <tr>
+<td><span class="new_code">error()</span></td>
+<td>Sends an exception event</td>
+</tr>
+ <tr>
+<td><span class="new_code">signal($type, $payload)</span></td>
+<td>Sends a user defined message to the test reporter</td>
+</tr>
+ <tr>
+<td><span class="new_code">dump($var)</span></td>
+<td>Does a formatted <span class="new_code">print_r()</span> for quick and dirty debugging</td>
+</tr>
+ </tbody></table>
+ </p>
+
+ <p><a class="target" name="extending_unit"><h2>Extending test cases</h2></a></p>
+ <p>
+ Of course additional test methods can be added to create
+ specific types of test case, so as to extend framework...
+<pre>
+require_once('simpletest/autorun.php');
+<strong>
+class FileTester extends UnitTestCase {
+ function FileTester($name = false) {
+ $this-&gt;UnitTestCase($name);
+ }
+
+ function assertFileExists($filename, $message = '%s') {
+ $this-&gt;assertTrue(
+ file_exists($filename),
+ sprintf($message, 'File [$filename] existence check'));
+ }</strong>
+}
+</pre>
+ Here the SimpleTest library is held in a folder called
+ <em>simpletest</em> that is local.
+ Substitute your own path for this.
+ </p>
+ <p>
+ To prevent this test case being run accidently, it is
+ advisable to mark it as <span class="new_code">abstract</span>.
+ </p>
+ <p>
+ Alternatively you could add a
+ <span class="new_code">SimpleTestOptions::ignore('FileTester');</span>
+ directive in your code.
+ </p>
+ <p>
+ This new case can be now be inherited just like
+ a normal test case...
+<pre>
+class FileTestCase extends <strong>FileTester</strong> {
+
+ function setUp() {
+ @unlink('../temp/test.txt');
+ }
+
+ function tearDown() {
+ @unlink('../temp/test.txt');
+ }
+
+ function testCreation() {
+ $writer = &amp;new FileWriter('../temp/test.txt');
+ $writer-&gt;write('Hello');<strong>
+ $this-&gt;assertFileExists('../temp/test.txt');</strong>
+ }
+}
+</pre>
+ </p>
+ <p>
+ If you want a test case that does not have all of the
+ <span class="new_code">UnitTestCase</span> assertions,
+ only your own and a few basics,
+ you need to extend the <span class="new_code">SimpleTestCase</span>
+ class instead.
+ It is found in <em>simple_test.php</em> rather than
+ <em>unit_tester.php</em>.
+ See <a href="group_test_documentation.html">later</a> if you
+ want to incorporate other unit tester's
+ test cases in your test suites.
+ </p>
+
+ <p><a class="target" name="running_unit"><h2>Running a single test case</h2></a></p>
+ <p>
+ You won't often run single test cases except when bashing
+ away at a module that is having difficulty, and you don't
+ want to upset the main test suite.
+ With <em>autorun</em> no particular scaffolding is needed,
+ just launch your particular test file and you're ready to go.
+ </p>
+ <p>
+ You can even decide which reporter (for example,
+ <span class="new_code">TextReporter</span> or <span class="new_code">HtmlReporter</span>)
+ you prefer for a specific file when launched on its own...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');<strong>
+SimpleTest :: prefer(new TextReporter());</strong>
+require_once('../classes/writer.php');
+
+class FileTestCase extends UnitTestCase {
+ ...
+}
+?&gt;
+</pre>
+ This script will run as is, but of course will output zero passes
+ and zero failures until test methods are added.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ <a href="http://simpletest.org/api/">Full API for SimpleTest</a>
+ from the PHPDoc.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <span class="chosen">Unit tester</span>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <a href="web_tester_documentation.html">Web tester</a>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>
diff --git a/vendors/simpletest/docs/en/web_tester_documentation.html b/vendors/simpletest/docs/en/web_tester_documentation.html
new file mode 100644
index 000000000..2602dd56d
--- /dev/null
+++ b/vendors/simpletest/docs/en/web_tester_documentation.html
@@ -0,0 +1,584 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Simple Test for PHP web script testing documentation</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <span class="chosen">Web tester</span>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<h1>Web tester documentation</h1>
+ This page...
+ <ul>
+<li>
+ Successfully <a href="#fetch">fetching a web page</a>
+ </li>
+<li>
+ Testing the <a href="#content">page content</a>
+ </li>
+<li>
+ <a href="#navigation">Navigating a web site</a>
+ while testing
+ </li>
+<li>
+ <a href="#request">Raw request modifications</a> and debugging methods
+ </li>
+</ul>
+<div class="content">
+ <p><a class="target" name="fetch"><h2>Fetching a page</h2></a></p>
+ <p>
+ Testing classes is all very well, but PHP is predominately
+ a language for creating functionality within web pages.
+ How do we test the front end presentation role of our PHP
+ applications?
+ Well the web pages are just text, so we should be able to
+ examine them just like any other test data.
+ </p>
+ <p>
+ This leads to a tricky issue.
+ If we test at too low a level, testing for matching tags
+ in the page with pattern matching for example, our tests will
+ be brittle.
+ The slightest change in layout could break a large number of
+ tests.
+ If we test at too high a level, say using mock versions of a
+ template engine, then we lose the ability to automate some classes
+ of test.
+ For example, the interaction of forms and navigation will
+ have to be tested manually.
+ These types of test are extremely repetitive and error prone.
+ </p>
+ <p>
+ SimpleTest includes a special form of test case for the testing
+ of web page actions.
+ The <span class="new_code">WebTestCase</span> includes facilities
+ for navigation, content and cookie checks and form handling.
+ Usage of these test cases is similar to the
+ <a href="unit_tester_documentation.html">UnitTestCase</a>...
+<pre>
+<strong>class TestOfLastcraft extends WebTestCase {
+}</strong>
+</pre>
+ Here we are about to test the
+ <a href="http://www.lastcraft.com/">Last Craft</a> site itself.
+ If this test case is in a file called <em>lastcraft_test.php</em>
+ then it can be loaded in a runner script just like unit tests...
+<pre>
+&lt;?php
+require_once('simpletest/autorun.php');<strong>
+require_once('simpletest/web_tester.php');</strong>
+SimpleTest::prefer(new TextReporter());
+
+class WebTests extends TestSuite {
+ function WebTests() {
+ $this-&gt;TestSuite('Web site tests');<strong>
+ $this-&gt;addFile('lastcraft_test.php');</strong>
+ }
+}
+?&gt;
+</pre>
+ I am using the text reporter here to more clearly
+ distinguish the web content from the test output.
+ </p>
+ <p>
+ Nothing is being tested yet.
+ We can fetch the home page by using the
+ <span class="new_code">get()</span> method...
+<pre>
+class TestOfLastcraft extends WebTestCase {
+ <strong>
+ function testHomepage() {
+ $this-&gt;assertTrue($this-&gt;get('http://www.lastcraft.com/'));
+ }</strong>
+}
+</pre>
+ The <span class="new_code">get()</span> method will
+ return true only if page content was successfully
+ loaded.
+ It is a simple, but crude way to check that a web page
+ was actually delivered by the web server.
+ However that content may be a 404 response and yet
+ our <span class="new_code">get()</span> method will still return true.
+ </p>
+ <p>
+ Assuming that the web server for the Last Craft site is up
+ (sadly not always the case), we should see...
+<pre class="shell">
+Web site tests
+OK
+Test cases run: 1/1, Failures: 0, Exceptions: 0
+</pre>
+ All we have really checked is that any kind of page was
+ returned.
+ We don't yet know if it was the right one.
+ </p>
+
+ <p><a class="target" name="content"><h2>Testing page content</h2></a></p>
+ <p>
+ To confirm that the page we think we are on is actually the
+ page we are on, we need to verify the page content.
+<pre>
+class TestOfLastcraft extends WebTestCase {
+
+ function testHomepage() {<strong>
+ $this-&gt;get('http://www.lastcraft.com/');
+ $this-&gt;assertText('Why the last craft');</strong>
+ }
+}
+</pre>
+ The page from the last fetch is held in a buffer in
+ the test case, so there is no need to refer to it directly.
+ The pattern match is always made against the buffer.
+ </p>
+ <p>
+ Here is the list of possible content assertions...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">assertTitle($title)</span></td>
+<td>Pass if title is an exact match</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertText($text)</span></td>
+<td>Pass if matches visible and "alt" text</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoText($text)</span></td>
+<td>Pass if doesn't match visible and "alt" text</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertPattern($pattern)</span></td>
+<td>A Perl pattern match against the page content</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoPattern($pattern)</span></td>
+<td>A Perl pattern match to not find content</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertLink($label)</span></td>
+<td>Pass if a link with this text is present</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoLink($label)</span></td>
+<td>Pass if no link with this text is present</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertLinkById($id)</span></td>
+<td>Pass if a link with this id attribute is present</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoLinkById($id)</span></td>
+<td>Pass if no link with this id attribute is present</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertField($name, $value)</span></td>
+<td>Pass if an input tag with this name has this value</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertFieldById($id, $value)</span></td>
+<td>Pass if an input tag with this id has this value</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertResponse($codes)</span></td>
+<td>Pass if HTTP response matches this list</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertMime($types)</span></td>
+<td>Pass if MIME type is in this list</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertAuthentication($protocol)</span></td>
+<td>Pass if the current challenge is this protocol</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoAuthentication()</span></td>
+<td>Pass if there is no current challenge</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertRealm($name)</span></td>
+<td>Pass if the current challenge realm matches</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertHeader($header, $content)</span></td>
+<td>Pass if a header was fetched matching this value</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoHeader($header)</span></td>
+<td>Pass if a header was not fetched</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertCookie($name, $value)</span></td>
+<td>Pass if there is currently a matching cookie</td>
+</tr>
+ <tr>
+<td><span class="new_code">assertNoCookie($name)</span></td>
+<td>Pass if there is currently no cookie of this name</td>
+</tr>
+ </tbody></table>
+ As usual with the SimpleTest assertions, they all return
+ false on failure and true on pass.
+ They also allow an optional test message and you can embed
+ the original test message inside using "%s" inside
+ your custom message.
+ </p>
+ <p>
+ So now we could instead test against the title tag with...
+<pre>
+<strong>$this-&gt;assertTitle('The Last Craft? Web developer tutorials on PHP, Extreme programming and Object Oriented development');</strong>
+</pre>
+ ...or, if that is too long and fragile...
+<pre>
+<strong>$this-&gt;assertTitle(new PatternExpectation('/The Last Craft/'));</strong>
+</pre>
+ As well as the simple HTML content checks we can check
+ that the MIME type is in a list of allowed types with...
+<pre>
+<strong>$this-&gt;assertMime(array('text/plain', 'text/html'));</strong>
+</pre>
+ More interesting is checking the HTTP response code.
+ Like the MIME type, we can assert that the response code
+ is in a list of allowed values...
+<pre>
+class TestOfLastcraft extends WebTestCase {
+
+ function testRedirects() {
+ $this-&gt;get('http://www.lastcraft.com/test/redirect.php');
+ $this-&gt;assertResponse(200);&lt;/strong&gt;
+ }
+}
+</pre>
+ Here we are checking that the fetch is successful by
+ allowing only a 200 HTTP response.
+ This test will pass, but it is not actually correct to do so.
+ There is no page, instead the server issues a redirect.
+ The <span class="new_code">WebTestCase</span> will
+ automatically follow up to three such redirects.
+ The tests are more robust this way and we are usually
+ interested in the interaction with the pages rather
+ than their delivery.
+ If the redirects are of interest then this ability must
+ be disabled...
+<pre>
+class TestOfLastcraft extends WebTestCase {
+
+ function testHomepage() {<strong>
+ $this-&gt;setMaximumRedirects(0);</strong>
+ $this-&gt;get('http://www.lastcraft.com/test/redirect.php');
+ $this-&gt;assertResponse(200);
+ }
+}
+</pre>
+ The assertion now fails as expected...
+<pre class="shell">
+Web site tests
+1) Expecting response in [200] got [302]
+ in testhomepage
+ in testoflastcraft
+ in lastcraft_test.php
+FAILURES!!!
+Test cases run: 1/1, Failures: 1, Exceptions: 0
+</pre>
+ We can modify the test to correctly assert redirects with...
+<pre>
+class TestOfLastcraft extends WebTestCase {
+
+ function testHomepage() {
+ $this-&gt;setMaximumRedirects(0);
+ $this-&gt;get('http://www.lastcraft.com/test/redirect.php');
+ $this-&gt;assertResponse(<strong>array(301, 302, 303, 307)</strong>);
+ }
+}
+</pre>
+ This now passes.
+ </p>
+
+ <p><a class="target" name="navigation"><h2>Navigating a web site</h2></a></p>
+ <p>
+ Users don't often navigate sites by typing in URLs, but by
+ clicking links and buttons.
+ Here we confirm that the contact details can be reached
+ from the home page...
+<pre>
+class TestOfLastcraft extends WebTestCase {
+ ...
+ function testContact() {
+ $this-&gt;get('http://www.lastcraft.com/');<strong>
+ $this-&gt;clickLink('About');
+ $this-&gt;assertTitle(new PatternExpectation('/About Last Craft/'));</strong>
+ }
+}
+</pre>
+ The parameter is the text of the link.
+ </p>
+ <p>
+ If the target is a button rather than an anchor tag, then
+ <span class="new_code">clickSubmit()</span> can be used
+ with the button title...
+<pre>
+<strong>$this-&gt;clickSubmit('Go!');</strong>
+</pre>
+ If you are not sure or don't care, the usual case, then just
+ use the <span class="new_code">click()</span> method...
+<pre>
+<strong>$this-&gt;click('Go!');</strong>
+</pre>
+ </p>
+ <p>
+ The list of navigation methods is...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">getUrl()</span></td>
+<td>The current location</td>
+</tr>
+ <tr>
+<td><span class="new_code">get($url, $parameters)</span></td>
+<td>Send a GET request with these parameters</td>
+</tr>
+ <tr>
+<td><span class="new_code">post($url, $parameters)</span></td>
+<td>Send a POST request with these parameters</td>
+</tr>
+ <tr>
+<td><span class="new_code">head($url, $parameters)</span></td>
+<td>Send a HEAD request without replacing the page content</td>
+</tr>
+ <tr>
+<td><span class="new_code">retry()</span></td>
+<td>Reload the last request</td>
+</tr>
+ <tr>
+<td><span class="new_code">back()</span></td>
+<td>Like the browser back button</td>
+</tr>
+ <tr>
+<td><span class="new_code">forward()</span></td>
+<td>Like the browser forward button</td>
+</tr>
+ <tr>
+<td><span class="new_code">authenticate($name, $password)</span></td>
+<td>Retry after a challenge</td>
+</tr>
+ <tr>
+<td><span class="new_code">restart()</span></td>
+<td>Restarts the browser as if a new session</td>
+</tr>
+ <tr>
+<td><span class="new_code">getCookie($name)</span></td>
+<td>Gets the cookie value for the current context</td>
+</tr>
+ <tr>
+<td><span class="new_code">ageCookies($interval)</span></td>
+<td>Ages current cookies prior to a restart</td>
+</tr>
+ <tr>
+<td><span class="new_code">clearFrameFocus()</span></td>
+<td>Go back to treating all frames as one page</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickSubmit($label)</span></td>
+<td>Click the first button with this label</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickSubmitByName($name)</span></td>
+<td>Click the button with this name attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickSubmitById($id)</span></td>
+<td>Click the button with this ID attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickImage($label, $x, $y)</span></td>
+<td>Click an input tag of type image by title or alt text</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickImageByName($name, $x, $y)</span></td>
+<td>Click an input tag of type image by name</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickImageById($id, $x, $y)</span></td>
+<td>Click an input tag of type image by ID attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">submitFormById($id)</span></td>
+<td>Submit a form without the submit value</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickLink($label, $index)</span></td>
+<td>Click an anchor by the visible label text</td>
+</tr>
+ <tr>
+<td><span class="new_code">clickLinkById($id)</span></td>
+<td>Click an anchor by the ID attribute</td>
+</tr>
+ <tr>
+<td><span class="new_code">getFrameFocus()</span></td>
+<td>The name of the currently selected frame</td>
+</tr>
+ <tr>
+<td><span class="new_code">setFrameFocusByIndex($choice)</span></td>
+<td>Focus on a frame counting from 1</td>
+</tr>
+ <tr>
+<td><span class="new_code">setFrameFocus($name)</span></td>
+<td>Focus on a frame by name</td>
+</tr>
+ </tbody></table>
+ </p>
+ <p>
+ The parameters in the <span class="new_code">get()</span>, <span class="new_code">post()</span> or
+ <span class="new_code">head()</span> methods are optional.
+ The HTTP HEAD fetch does not change the browser context, only loads
+ cookies.
+ This can be useful for when an image or stylesheet sets a cookie
+ for crafty robot blocking.
+ </p>
+ <p>
+ The <span class="new_code">retry()</span>, <span class="new_code">back()</span> and
+ <span class="new_code">forward()</span> commands work as they would on
+ your web browser.
+ They use the history to retry pages.
+ This can be handy for checking the effect of hitting the
+ back button on your forms.
+ </p>
+ <p>
+ The frame methods need a little explanation.
+ By default a framed page is treated just like any other.
+ Content will be searced for throughout the entire frameset,
+ so clicking a link will work no matter which frame
+ the anchor tag is in.
+ You can override this behaviour by focusing on a single
+ frame.
+ If you do that, all searches and actions will apply to that
+ frame alone, such as authentication and retries.
+ If a link or button is not in a focused frame then it cannot
+ be clicked.
+ </p>
+ <p>
+ Testing navigation on fixed pages only tells you when you
+ have broken an entire script.
+ For highly dynamic pages, such as for bulletin boards, this can
+ be crucial for verifying the correctness of the application.
+ For most applications though, the really tricky logic is usually in
+ the handling of forms and sessions.
+ Fortunately SimpleTest includes
+ <a href="form_testing_documentation.html">tools for testing web forms</a>
+ as well.
+ </p>
+
+ <p><a class="target" name="request"><h2>Modifying the request</h2></a></p>
+ <p>
+ Although SimpleTest does not have the goal of testing networking
+ problems, it does include some methods to modify and debug
+ the requests it makes.
+ Here is another method list...
+ <table><tbody>
+ <tr>
+<td><span class="new_code">getTransportError()</span></td>
+<td>The last socket error</td>
+</tr>
+ <tr>
+<td><span class="new_code">showRequest()</span></td>
+<td>Dump the outgoing request</td>
+</tr>
+ <tr>
+<td><span class="new_code">showHeaders()</span></td>
+<td>Dump the incoming headers</td>
+</tr>
+ <tr>
+<td><span class="new_code">showSource()</span></td>
+<td>Dump the raw HTML page content</td>
+</tr>
+ <tr>
+<td><span class="new_code">ignoreFrames()</span></td>
+<td>Do not load framesets</td>
+</tr>
+ <tr>
+<td><span class="new_code">setCookie($name, $value)</span></td>
+<td>Set a cookie from now on</td>
+</tr>
+ <tr>
+<td><span class="new_code">addHeader($header)</span></td>
+<td>Always add this header to the request</td>
+</tr>
+ <tr>
+<td><span class="new_code">setMaximumRedirects($max)</span></td>
+<td>Stop after this many redirects</td>
+</tr>
+ <tr>
+<td><span class="new_code">setConnectionTimeout($timeout)</span></td>
+<td>Kill the connection after this time between bytes</td>
+</tr>
+ <tr>
+<td><span class="new_code">useProxy($proxy, $name, $password)</span></td>
+<td>Make requests via this proxy URL</td>
+</tr>
+ </tbody></table>
+ These methods are principally for debugging.
+ </p>
+
+ </div>
+ References and related information...
+ <ul>
+<li>
+ SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
+ </li>
+<li>
+ SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
+ </li>
+<li>
+ The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
+ gives full detail on the classes and assertions available.
+ </li>
+</ul>
+<div class="menu_back"><div class="menu">
+<a href="index.html">SimpleTest</a>
+ |
+ <a href="overview.html">Overview</a>
+ |
+ <a href="unit_test_documentation.html">Unit tester</a>
+ |
+ <a href="group_test_documentation.html">Group tests</a>
+ |
+ <a href="mock_objects_documentation.html">Mock objects</a>
+ |
+ <a href="partial_mocks_documentation.html">Partial mocks</a>
+ |
+ <a href="reporter_documentation.html">Reporting</a>
+ |
+ <a href="expectation_documentation.html">Expectations</a>
+ |
+ <span class="chosen">Web tester</span>
+ |
+ <a href="form_testing_documentation.html">Testing forms</a>
+ |
+ <a href="authentication_documentation.html">Authentication</a>
+ |
+ <a href="browser_documentation.html">Scriptable browser</a>
+</div></div>
+<div class="copyright">
+ Copyright<br>Marcus Baker 2006
+ </div>
+</body>
+</html>