diff options
Diffstat (limited to 'vendors/simpletest/docs/en')
| -rwxr-xr-x | vendors/simpletest/docs/en/authentication_documentation.html | 355 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/browser_documentation.html | 447 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/docs.css | 121 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/expectation_documentation.html | 422 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/form_testing_documentation.html | 342 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/group_test_documentation.html | 386 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/index.html | 538 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/mock_objects_documentation.html | 757 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/overview.html | 486 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/partial_mocks_documentation.html | 445 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/reporter_documentation.html | 519 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/unit_test_documentation.html | 431 | ||||
| -rwxr-xr-x | vendors/simpletest/docs/en/web_tester_documentation.html | 584 | 
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 100755 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->get('http://www.lastcraft.com/protected/'); +        $this->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->get('http://www.lastcraft.com/protected/');<strong> +        $this->assertAuthentication('Basic'); +        $this->assertResponse(401); +        $this->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->get('http://www.lastcraft.com/protected/'); +        $this->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->get('http://www.lastcraft.com/protected/');<strong> +        $this->authenticate('Me', 'Secret');</strong> +        $this->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->get('http://<strong>Me:Secret@</strong>www.lastcraft.com/protected/'); +        $this->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> +<form> +    Username: +    <input type="text" name="u" value="" /><br /> +    Password: +    <input type="password" name="p" value="" /><br /> +    <input type="submit" value="Log in" /> +</form> +</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->get('http://www.my-site.com/login.php');<strong> +        $this->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->get('http://www.my-site.com/login.php'); +        $this->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->get('http://www.my-site.com/login.php');<strong> +        $session = $this->getCookie('SID'); +        $this->setField('u', 'Me'); +        $this->setField('p', 'Secret'); +        $this->click('Log in'); +        $this->assertText('Welcome Me'); +        $this->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->get('http://www.my-site.com/login.php');<strong> +        $this->setCookie('SID', 'Some other session'); +        $this->get('http://www.my-site.com/restricted.php');</strong> +        $this->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->get('http://www.my-site.com/login.php'); +        $this->setField('u', 'Me'); +        $this->setField('p', 'Secret'); +        $this->click('Log in'); +        $this->assertText('Welcome Me');<strong> +         +        $this->restart(); +        $this->get('http://www.my-site.com/restricted.php'); +        $this->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->get('http://www.my-site.com/login.php'); +        $this->setField('u', 'Me'); +        $this->setField('p', 'Secret'); +        $this->click('Log in'); +        $this->assertText('Welcome Me'); +        <strong> +        $this->ageCookies(3600);</strong> +        $this->restart(); +        $this->get('http://www.my-site.com/restricted.php'); +        $this->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 100755 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><?php +require_once('simpletest/browser.php'); +     +$browser = &new SimpleBrowser(); +$browser->get('http://php.net/'); +$browser->click('reporting bugs'); +$browser->click('statistics'); +$page = $browser->click('PHP 5 bugs only'); +preg_match('/status=Open.*?by=Any.*?(\d+)<\/a>/', $page, $matches); +print $matches[1]; +?></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 = &new SimpleBrowser(); +        $browser->get('http://my-site.com/register.php'); +        $browser->setField('email', 'me@here'); +        $browser->setField('password', 'Secret'); +        $browser->click('Register'); +        <strong> +        $authenticator = &new Authenticator(); +        $member = &$authenticator->findByEmail('me@here'); +        $this->assertEqual($member->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 = &new SimpleBrowser(); +        $first->get('http://my-site.com/login.php'); +        $first->setField('name', 'Me'); +        $first->setField('password', 'Secret'); +        $first->click('Enter'); +        $this->assertEqual($first->getTitle(), 'Welcome'); +         +        $second = &new SimpleBrowser(); +        $second->get('http://my-site.com/login.php'); +        $second->setField('name', 'Me'); +        $second->setField('password', 'Secret'); +        $second->click('Enter'); +        $this->assertEqual($second->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 100755 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 100755 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(&$writer) { +        if (! $this->isConnected()) { +            $writer->write('Cannot connect to news service "' . +                    $this->_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 = &new MockWriter(); +        $writer->expectOnce('write', array( +                'Cannot connect to news service ' . +                '"BBC News" at this time. ' . +                'Please try again later.')); +         +        $service = &new NewsService('BBC News'); +        $service->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 = &new MockWriter();<strong> +        $writer->expectOnce( +                'write', +                array(new PatternExpectation('/cannot connect/i')));</strong> +         +        $service = &new NewsService('BBC News'); +        $service->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->expectOnce('method', array(new IdenticalExpectation(14))); +</pre> +                This is the same as <span class="new_code">$mock->expectOnce('method', array(14))</span>. +<pre> +$mock->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->expectOnce('method', array(new AnythingExpectation(14))); +</pre> +                This is the same as <span class="new_code">$mock->expectOnce('method', array('*'))</span>. +<pre> +$mock->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->setReturnValue( +        'isAllowed', +        true, +        array(new IsAExpectation('Session', 'Must be a session'))); +$authorisation->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 = &new Server(); +        $this->assert( +                new ValidIp(), +                $server->getIp(), +                'Server IP address->%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->assert(new ValidIp(), $ip, $message); +    }</strong> +     +    function testGetValidIp() { +        $server = &new Server();<strong> +        $this->assertValidIp( +                $server->getIp(), +                'Server IP address->%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 100755 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 <form> tags +                being available from within the test case. +                For example, if we have this snippet of HTML... +<pre> +<form> +    <input type="text" name="a" value="A default" /> +    <input type="submit" value="Go" /> +</form> +</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->get('http://www.lastcraft.com/form_testing_documentation.php'); +        $this->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->get('http://www.my-site.com/'); +        $this->assertField('a', 'A default');<strong> +        $this->setField('a', 'New value'); +        $this->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> +<strong>Select type of user to add:</strong> +<select name="type"> +    <option>Subscriber</option> +    <option>Author</option> +    <option>Administrator</option> +</select> +</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->get('http://www.lastcraft.com/form_testing_documentation.php'); +        $this->assertFalse($this->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> +<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> +</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->get('http://www.lastcraft.com/form_testing_documentation.php'); +        $this->assertField('crud', array('c', 'r', 'u', 'd')); +        $this->setField('crud', array('r')); +        $this->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->setField('a_hidden_field', '123'); +        $this->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->clickSubmit('OK', array('a_hidden_field'=>'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->post( +                'http://www.my-site.com/add_user.php', +                array('type' => 'superuser')); +        $this->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 100755 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><?php +    require_once('../classes/io.php'); + +    class FileTester extends UnitTestCase { +        ... +    } + +    class SocketTester extends UnitTestCase { +        ... +    } +?></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> +<?php +    require_once('../classes/io.php'); +<strong> +    class MyFileTestCase extends UnitTestCase { +        ... +    } +    SimpleTest::ignore('MyFileTestCase');</strong> + +    class FileTester extends MyFileTestCase { ... } + +    class SocketTester extends UnitTestCase { ... } +?> +</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> +<?php +    require_once('simpletest/unit_tester.php'); +    require_once('simpletest/reporter.php');<strong> +    require_once('file_test.php'); + +    $test = &new TestSuite('All file tests'); +    $test->addTestCase(new FileTestCase()); +    $test->run(new HtmlReporter());</strong> +?> +</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> +<?php +    require_once('simpletest/unit_tester.php'); +    require_once('simpletest/reporter.php'); + +    $test = &new TestSuite('All file tests');<strong> +    $test->addTestFile('file_test.php');</strong> +    $test->run(new HtmlReporter()); +?&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> +<?php +    require_once('simpletest/unit_tester.php'); +    require_once('simpletest/reporter.php'); +    <strong> +    class FileTestSuite extends TestSuite { +        function FileTestSuite() { +            $this->TestSuite('All file tests'); +            $this->addTestFile('file_test.php'); +        } +    }</strong> +?> +</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> +<?php +    require_once('file_test_suite.php'); +    <strong> +    $test = &new FileTestSuite(); +    $test->run(new HtmlReporter());</strong> +?> +</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> +<?php +    <strong> +    $test = &new BigTestSuite('Big group'); +    $test->addTestFile('file_test_suite.php'); +    $test->addTestFile('some_test_case.php');</strong> +    $test->run(new HtmlReporter()); +?> +</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> +<?php +    class FileTestSuite extends TestSuite { +        function FileTestSuite() { +            $this->TestSuite('All file tests'); +            $test->addTestFile('file_test.php'); +        } +    } +    <strong> +    if (! defined('RUNNER')) { +        define('RUNNER', true);</strong> +        $test = &new FileTestSuite(); +        $test->run(new HtmlReporter()); +    } +?> +</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> +<?php<strong> +    define('RUNNER', true);</strong> +    require_once('file_test_suite.php'); + +    $test = &new BigTestSuite('Big group'); +    $test->addTestCase(new FileTestSuite()); +    $test->addTestCase(...); +    $test->run(new HtmlReporter()); +?> +</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> +<?php +    define('RUNNER', true); + +    $test = &new BigTestSuite('Big group');<strong> +    $test->addTestFile('file_test_suite.php'); +    $test->addTestFile(...);</strong> +    $test->run(new HtmlReporter()); +?> +</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->TestCase('Config file test'); +    } +     +    function testContents() { +        $config = new ConfigFile('test.conf'); +        $this->assertRegexp('/me/', $config->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> +<?php +    require_once('simpletest/unit_tester.php'); +    require_once('simpletest/reporter.php');<strong> +    require_once('simpletest/adapters/phpunit_test_case.php');</strong> + +    $test = &new TestSuite('All file tests');<strong> +    $test->addTestFile('config_test.php');</strong> +    $test->run(new HtmlReporter()); +?> +</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> +<?php +    require_once('simpletest/unit_tester.php'); +    require_once('simpletest/reporter.php');<strong> +    require_once('simpletest/adapters/pear_test_case.php');</strong> + +    $test = &new TestSuite('All file tests');<strong> +    $test->addTestFile('some_pear_test_cases.php');</strong> +    $test->run(new HtmlReporter()); +?> +</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 100755 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> +<?php +<strong>require_once('simpletest/autorun.php');</strong> +require_once('../classes/log.php'); + +class TestOfLogging extends <strong>UnitTestCase</strong> { +} +?> +</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> +<?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->assertFalse(file_exists('/temp/test.log'));</strong> +        $log->message('Should write this to a file'); +        <strong>$this->assertTrue(file_exists('/temp/test.log'));</strong> +    } +} +?> +</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->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> +<?php<strong> +class Log { +    function Log($file_path) { +    } + +    function message() { +    } +}</strong> +?> +</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> +<?php +<strong>require_once('simpletest/autorun.php');</strong> + +class AllTests extends <strong>TestSuite</strong> { +    function AllTests() { +        $this->TestSuite(<strong>'All tests'</strong>); +        <strong>$this->addFile('log_test.php');</strong> +    } +} +?> +</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->_log->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> +<?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 = &new SessionPool($log); +        $session_pool->logIn('fred');</strong> +        $messages = file('/temp/test.log'); +        $this->assertEqual($messages[0], "User fred logged in.<strong>\n</strong>"); +    } +} +?> +</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> +<?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 = &new MockLog(); +        $log->expectOnce('message', array('User fred logged in.'));</strong> +        $session_pool = &new SessionPool(<strong>$log</strong>); +        $session_pool->logIn('fred'); +    } +} +?> +</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> +<?php +require_once('simpletest/autorun.php'); +<strong>require_once('simpletest/web_tester.php');</strong> + +class TestOfAbout extends <strong>WebTestCase</strong> { +    function testOurAboutPageGivesFreeReignToOurEgo() { +        <strong>$this->get('http://test-server/index.php'); +        $this->click('About'); +        $this->assertTitle('About why we are so great'); +        $this->assertText('We are really great');</strong> +    } +} +?> +</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> +<?php +require_once('simpletest/autorun.php'); +require_once('simpletest/web_tester.php'); + +class TestOfRankings extends WebTestCase { +    function testWeAreTopOfGoogle() { +        $this->get('http://google.com/'); +        $this->setField('q', 'simpletest'); +        $this->click("I'm Feeling Lucky"); +        $this->assertTitle('SimpleTest - Unit Testing for PHP'); +    } +} +?> +</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&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&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 100755 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 = &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->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->setReturnValue('query', 37)</strong> +</pre> +                Now every time we call +                <span class="new_code">$connection->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 = &new MockIterator(); +        $iterator->setReturnValue('next', false); +        $iterator->setReturnValueAt(0, 'next', 'First string'); +        $iterator->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 = &new MockConfiguration(); +$config->setReturnValue('getValue', 'primary', array('db_host')); +$config->setReturnValue('getValue', 'admin', array('db_user')); +$config->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->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->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->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 = &new Thing();<strong> +$vector = &new MockVector(); +$vector->setReturnReference('get', $thing, array(12));</strong> +</pre> +                With this arrangement you know that every time +                <span class="new_code">$vector->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 = &new MockComplexThing(); +$stuff = &new Stuff();<strong> +$complex->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 = &new MockResultIterator(); +        $result->setReturnValue('next', false); +        $result->setReturnValueAt(0, 'next', array(1, 'tom')); +        $result->setReturnValueAt(1, 'next', array(3, 'dick')); +        $result->setReturnValueAt(2, 'next', array(6, 'harry')); +         +        $connection = &new MockDatabaseConnection(); +        $connection->setReturnValue('query', false); +        $connection->setReturnReference( +                'query', +                $result, +                array('select id, name from users'));</strong> +                 +        $finder = &new UserFinder($connection); +        $this->assertIdentical( +                $finder->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 &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(&$session_pool, &$log) { +        ... +    } +     +    function &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 = &new MockSession(); +        $pool = &new MockSessionPool(); +        $pool->setReturnReference('findSession', $session); +        $pool->expectOnce('findSession', array('abc')); +         +        $log = &new MockLog(); +        $log->expectOnce('message', array('Starting session abc')); +         +        $logging_pool = &new LoggingSessionPool($pool, $log); +        $this->assertReference($logging_pool->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->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> +<?php +    require_once('simpletest/mock_objects.php'); +    require_once('../classes/connection.php'); +<strong> +    Mock::generate('Connection', 'BasicMockConnection'); +    class MockConnection extends BasicMockConnection { +        function MockConnection() { +            $this->BasicMockConnection(); +            $this->setReturn('query', false); +        } +    }</strong> +?> +</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 100755 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> +<?php +require_once('simpletest/autorun.php'); + +class <strong>MyTestCase</strong> extends UnitTestCase { +    <strong> +    function testCreatedLogFile() { +        $log = &new Log('my.log'); +        $log->message('Hello'); +        $this->assertTrue(file_exists('my.log')); +    }</strong> +} +?> +</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> +<?php +require_once('simpletest/autorun.php'); +require_once('simpletest/web_tester.php'); + +class <strong>MySiteTest</strong> extends WebTestCase { +    <strong> +    function testHomePage() { +        $this->get('http://www.my-site.com/index.php'); +        $this->assertTitle('My Home Page'); +        $this->clickLink('Contact'); +        $this->assertTitle('Contact me'); +        $this->assertPattern('/Email me at/'); +    }</strong> +} +?> +</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 100755 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><?php +require_once('socket.php'); +     +class Telnet { +    ... +    function &connect($ip, $port, $username, $password) { +        $socket = &new Socket($ip, $port); +        $socket->read( ... ); +        ... +    } +} +?></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> +<?php +require_once('socket.php'); +     +class Telnet { +    ... +    <strong>function &connect(&$socket, $username, $password) { +        $socket->read( ... ); +        ... +    }</strong> +} +?> +</pre> +                This means that the test code is typical for a test involving +                mock objects. +<pre> +class TelnetTest extends UnitTestCase { +    ... +    function testConnection() {<strong> +        $socket = &new MockSocket($this); +        ... +        $telnet = &new Telnet(); +        $telnet->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> +<?php +require_once('socket.php'); +     +class Telnet { +    ...<strong> +    function &connect($ip, $port, $username, $password, $socket = false) { +        if (!$socket) { +            $socket = &new Socket($ip, $port); +        } +        $socket->read( ... );</strong> +        ... +        return $socket; +    } +} +?> +</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 = &new MockSocket($this); +        ... +        $telnet = &new Telnet(); +        $telnet->connect('127.0.0.1', 21, 'Me', 'Secret', &$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> +<?php +require_once('socket.php'); +     +class Telnet {<strong> +   function Telnet(&$network) { +        $this->_network = &$network; +    }</strong> +    ... +    function &connect($ip, $port, $username, $password) {<strong> +        $socket = &$this->_network->createSocket($ip, $port); +        $socket->read( ... );</strong> +        ... +        return $socket; +    } +} +?> +</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 = &new MockSocket($this); +        ... +        $network = &new MockNetwork($this); +        $network->setReturnReference('createSocket', $socket); +        $telnet = &new Telnet($network); +        $telnet->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> +<?php +require_once('socket.php'); +     +class Telnet { +    ... +    function &connect($ip, $port, $username, $password) {<strong> +        $socket = &$this->_createSocket($ip, $port);</strong> +        $socket->read( ... ); +        ... +    }<strong> +         +    function &_createSocket($ip, $port) { +        return new Socket($ip, $port); +    }</strong> +} +?> +</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(&$mock) { +        $this->_mock = &$mock; +        $this->Telnet(); +    } +     +    function &_createSocket() { +        return $this->_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 = &new MockSocket($this); +        ... +        $telnet = &new TelnetTestVersion($socket); +        $telnet->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 = &new MockSocket($this); +        ... +        $telnet = &new TelnetTestVersion($this); +        $telnet->setReturnReference('_createSocket', $socket); +        $telnet->Telnet(); +        $telnet->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 = &new MockSocket($this); +        ... +        $telnet = &new TelnetTestVersion($this); +        $telnet->setReturnReference('_createSocket', $socket);<strong> +        $telnet->expectOnce('_createSocket', array('127.0.0.1', 21));</strong> +        $telnet->Telnet(); +        $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); +        ...<strong> +        $telnet->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 100755 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->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 "&<span class=\"pass\">Pass</span>: "; +        $breadcrumb = $this->getTestList(); +        array_shift($breadcrumb); +        print implode("-&gt;", $breadcrumb); +        print "-&gt;$message<br />\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> +<?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); + +$test = &new TestSuite('File test'); +$test->addTestFile('tests/file_test.php'); +$test->run(<strong>new TextReporter()</strong>); +?> +</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> +<?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); + +$test = &new TestSuite('File test'); +$test->addTestFile('tests/file_test.php'); +<strong>exit ($test->run(new TextReporter()) ? 0 : 1);</strong> +?> +</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> +<?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); + +$test = &new TestSuite('File test'); +$test->addTestFile('tests/file_test.php'); +<strong>if (TextReporter::inCli()) {</strong> +    exit ($test->run(new TextReporter()) ? 0 : 1); +<strong>}</strong> +$test->run(new HtmlReporter()); +?> +</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"> +<?xml version="1.0"?> +<run> +  <group size="4"> +    <name>Remote tests</name> +    <group size="4"> +      <name>Visual test with 48 passes, 48 fails and 4 exceptions</name> +      <case> +        <name>testofunittestcaseoutput</name> +        <test> +          <name>testofresults</name> +          <pass>This assertion passed</pass> +          <fail>This assertion failed</fail> +        </test> +        <test> +          ... +        </test> +      </case> +    </group> +  </group> +</run> +</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> +<?php +require_once('simpletest/xml.php'); +     +... +$parser = &new SimpleTestXmlParser(new HtmlReporter()); +$parser->parse($test_output); +?> +</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> +<?php +<strong>require_once('../remote.php');</strong> +require_once('../reporter.php'); +     +$test_url = ...; +$dry_url = ...; +     +$test = &new TestSuite('Remote tests'); +$test->addTestCase(<strong>new RemoteTestCase($test_url, $dry_url)</strong>); +$test->run(new HtmlReporter()); +?> +</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 100755 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->UnitTestCase('File test'); +    }<strong> +     +    function setUp() { +        @unlink('../temp/test.txt'); +    } +     +    function tearDown() { +        @unlink('../temp/test.txt'); +    } +     +    function testCreation() { +        $writer = &new FileWriter('../temp/test.txt'); +        $writer->write('Hello'); +        $this->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) < $m is false</td> +</tr> +                    <tr> +<td><span class="new_code">assertOutsideMargin($x, $y, $m)</span></td> +<td>Fail if abs($x - $y) < $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->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->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->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->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->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->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->UnitTestCase($name); +    } +     +    function assertFileExists($filename, $message = '%s') { +        $this->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 = &new FileWriter('../temp/test.txt'); +        $writer->write('Hello');<strong> +        $this->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> +<?php +require_once('simpletest/autorun.php');<strong> +SimpleTest :: prefer(new TextReporter());</strong> +require_once('../classes/writer.php'); + +class FileTestCase extends UnitTestCase { +    ... +} +?> +</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 100755 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> +<?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->TestSuite('Web site tests');<strong> +        $this->addFile('lastcraft_test.php');</strong> +    } +} +?> +</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->assertTrue($this->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->get('http://www.lastcraft.com/'); +        $this->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->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->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->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->get('http://www.lastcraft.com/test/redirect.php'); +        $this->assertResponse(200);</strong> +    } +} +</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->setMaximumRedirects(0);</strong> +        $this->get('http://www.lastcraft.com/test/redirect.php'); +        $this->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->setMaximumRedirects(0); +        $this->get('http://www.lastcraft.com/test/redirect.php'); +        $this->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->get('http://www.lastcraft.com/');<strong> +        $this->clickLink('About'); +        $this->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->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->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> | 
