diff options
| author | wei <> | 2006-07-05 07:35:50 +0000 | 
|---|---|---|
| committer | wei <> | 2006-07-05 07:35:50 +0000 | 
| commit | b6dfb6c447cf502e694d299dbda1b2e092c3312d (patch) | |
| tree | b1bbd0abf857cca4b297d575942efa60edd12480 /test_tools/simpletest/docs/en/index.html | |
| parent | b5c7c7b77d33aa3e04ed6c16a489a2076a30f57a (diff) | |
move tests to test_tools
Diffstat (limited to 'test_tools/simpletest/docs/en/index.html')
| -rwxr-xr-x | test_tools/simpletest/docs/en/index.html | 467 | 
1 files changed, 467 insertions, 0 deletions
diff --git a/test_tools/simpletest/docs/en/index.html b/test_tools/simpletest/docs/en/index.html new file mode 100755 index 00000000..04797272 --- /dev/null +++ b/test_tools/simpletest/docs/en/index.html @@ -0,0 +1,467 @@ +<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"> +<h2> +<span class="chosen">SimpleTest</span> +</h2> +<ul> +<li> +<a href="overview.html">Overview</a> +</li> +<li> +<a href="unit_test_documentation.html">Unit tester</a> +</li> +<li> +<a href="group_test_documentation.html">Group tests</a> +</li> +<li> +<a href="server_stubs_documentation.html">Server stubs</a> +</li> +<li> +<a href="mock_objects_documentation.html">Mock objects</a> +</li> +<li> +<a href="partial_mocks_documentation.html">Partial mocks</a> +</li> +<li> +<a href="reporter_documentation.html">Reporting</a> +</li> +<li> +<a href="expectation_documentation.html">Expectations</a> +</li> +<li> +<a href="web_tester_documentation.html">Web tester</a> +</li> +<li> +<a href="form_testing_documentation.html">Testing forms</a> +</li> +<li> +<a href="authentication_documentation.html">Authentication</a> +</li> +<li> +<a href="browser_documentation.html">Scriptable browser</a> +</li> +</ul> +</div> +</div> +<h1>Simple Test for PHP</h1> +<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, but also adds +                <a href="http://www.mockobjects.com">mock objects</a>. +                It has some <a href="http://sourceforge.net/projects/jwebunit/">JWebUnit</a> +                functionality as well. +                This includes web page navigation, cookie testing and form submission. +            </p> +            <p> +                The quickest way to demonstrate 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> +<strong><?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); +require_once('../classes/log.php'); +?></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 +                placed the toolset. +                Next we create a test case... +<pre> +<?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); +require_once('../classes/log.php'); +<strong> +class TestOfLogging extends UnitTestCase { +}</strong> +?> +</pre> +                Now we have five lines of scaffolding code and still no tests. +                However from this part on we get return on our investment very quickly. +                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/unit_tester.php'); +require_once('simpletest/reporter.php'); +require_once('../classes/log.php'); + +class TestOfLogging extends UnitTestCase { +    <strong> +    function testCreatingNewFile() { +        @unlink('/temp/test.log'); +        $log = new Log('/temp/test.log'); +        $this->assertFalse(file_exists('/temp/test.log')); +        $log->message('Should write this to a file'); +        $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 <span class="new_code">test</span> +                and execute that method. +                We would normally have more than one test method of course. +                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 content right next to the test case concerned. +            </p> +            <p> +                To see these results we have to actually run the tests. +                If this is the only test case we wish to run we can achieve +                it with... +<pre> +<?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); +require_once('../classes/log.php'); + +class TestOfLogging extends UnitTestCase { +     +    function testCreatingNewFile() { +        @unlink('/temp/test.log'); +        $log = new Log('/temp/test.log'); +        $this->assertFalse(file_exists('/temp/test.log')); +        $log->message('Should write this to a file'); +        $this->assertTrue(file_exists('/temp/test.log')); +    } +} +<strong> +$test = &new TestOfLogging(); +$test->run(new HtmlReporter());</strong> +?> +</pre> +            </p> +            <p> +                On failure the display looks like this... +                <div class="demo"> +                    <h1>testoflogging</h1> +                    <span class="fail">Fail</span>: testcreatingnewfile->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 +class Log { +     +        function Log($file_path) { +        } + +		function message() { +		} +} +?>; +</pre> +            </p> +         +        <p> +<a class="target" name="group"> +<h2>Building group tests</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 in the application. +            </p> +            <p> +                Our first step is to strip the includes and to undo our +                previous hack... +<pre> +<?php<strong> +require_once('../classes/log.php');</strong> + +class TestOfLogging extends UnitTestCase { +     +    function testCreatingNewFile() { +        @unlink('/temp/test.log'); +        $log = new Log('/temp/test.log'); +        $this->assertFalse(file_exists('/temp/test.log')); +        $log->message('Should write this to a file'); +        $this->assertTrue(file_exists('/temp/test.log'));<strong> +    } +} +?></strong> +</pre> +                Next we create a new file called <em>tests/all_tests.php</em> +                and insert the following code... +<pre> +<strong><?php +require_once('simpletest/unit_tester.php'); +require_once('simpletest/reporter.php'); + +$test = &new GroupTest('All tests'); +$test->addTestFile('log_test.php'); +$test->run(new HtmlReporter()); +?></strong> +</pre> +                The method <span class="new_code">GroupTest::addTestFile()</span> +                will include the test case file and read any new classes created +                that are descended from <span class="new_code">SimpleTestCase</span>, of which +                <span class="new_code">UnitTestCase</span> is one example. +                Just the class names are stored for now, so that the test runner +                can instantiate the class when it works its way +                through your test suite. +            </p> +            <p> +                For this to work properly the test case file should not blindly include +                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 add +                a <span class="new_code">SimpleTestOptions::ignore()</span> directive +                somewhere in the test case file. +                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">GroupTest::addTestFile()</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. +            </p> +         +        <p> +<a class="target" name="mock"> +<h2>Using mock objects</h2> +</a> +</p> +            <p> +                Let's move further into the future. +            </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> +<strong> +<?php +require_once('../classes/log.php'); +require_once('../classes/session_pool.php'); + +class TestOfSessionLogging extends UnitTestCase { +     +    function setUp() { +        @unlink('/temp/test.log'); +    } +     +    function tearDown() { +        @unlink('/temp/test.log'); +    } +     +    function testLogInIsLogged() { +        $log = new Log('/temp/test.log'); +        $session_pool = &new SessionPool($log); +        $session_pool->logIn('fred'); +        $messages = file('/temp/test.log'); +        $this->assertEqual($messages[0], "User fred logged in.\n"); +    } +} +?></strong> +</pre> +                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. Worse, 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? +                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 reduce coupling if we can 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? +                Luckily we can create such an object easily... +<pre> +<?php +require_once('../classes/log.php'); +require_once('../classes/session_pool.php');<strong> +Mock::generate('Log');</strong> + +class TestOfSessionLogging extends UnitTestCase { +     +    function testLogInIsLogged() {<strong> +        $log = &new MockLog($this); +        $log->expectOnce('message', array('User fred logged in.'));</strong> +        $session_pool = &new SessionPool($log); +        $session_pool->logIn('fred');<strong> +        $log->tally();</strong> +    } +} +?> +</pre> +                The <span class="new_code">tally()</span> call is needed to +                tell the mock object that time is up for the expected call +                count. +                Without it the mock would wait forever for the method +                call to come in without ever actually notifying the test case. +                The other 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. +                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 as to prevent tests +                becoming too specific. +            </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 this test to run the mock objects library must have been +                included in the test suite, say in <em>all_tests.php</em>. +            </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, there is +                no JavaScript for example. +                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<strong> +require_once('simpletest/web_tester.php');</strong> +require_once('simpletest/reporter.php'); +<strong> +class TestOfAbout extends WebTestCase { +     +    function setUp() { +        $this->get('http://test-server/index.php'); +        $this->clickLink('About'); +    } +     +    function testSearchEngineOptimisations() { +        $this->assertTitle('A long title about us for search engines'); +        $this->assertWantedPattern('/a popular keyphrase/i'); +    } +}</strong> +$test = &new TestOfAbout(); +$test->run(new HtmlReporter()); +?> +</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> +                <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> +<div class="copyright"> +            Copyright<br>Marcus Baker, Jason Sweat, Perrick Penet 2004 +        </div> +</body> +</html>  | 
