summaryrefslogtreecommitdiff
path: root/tests/UnitTests/simpletest/docs/en/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'tests/UnitTests/simpletest/docs/en/index.html')
-rw-r--r--tests/UnitTests/simpletest/docs/en/index.html467
1 files changed, 467 insertions, 0 deletions
diff --git a/tests/UnitTests/simpletest/docs/en/index.html b/tests/UnitTests/simpletest/docs/en/index.html
new file mode 100644
index 00000000..d5a30d31
--- /dev/null
+++ b/tests/UnitTests/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>&lt;?php
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/reporter.php');
+require_once('../classes/log.php');
+?&gt;</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>
+&lt;?php
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/reporter.php');
+require_once('../classes/log.php');
+<strong>
+class TestOfLogging extends UnitTestCase {
+}</strong>
+?&gt;
+</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>
+&lt;?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-&gt;assertFalse(file_exists('/temp/test.log'));
+ $log-&gt;message('Should write this to a file');
+ $this-&gt;assertTrue(file_exists('/temp/test.log'));
+ }</strong>
+}
+?&gt;
+</pre>
+ When a test case runs it will search for any method that
+ starts with the string <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>
+&lt;?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-&gt;assertFalse(file_exists('/temp/test.log'));
+ $log-&gt;message('Should write this to a file');
+ $this-&gt;assertTrue(file_exists('/temp/test.log'));
+ }
+}
+<strong>
+$test = &amp;new TestOfLogging();
+$test-&gt;run(new HtmlReporter());</strong>
+?&gt;
+</pre>
+ </p>
+ <p>
+ On failure the display looks like this...
+ <div class="demo">
+ <h1>testoflogging</h1>
+ <span class="fail">Fail</span>: testcreatingnewfile-&gt;True assertion failed.<br>
+ <div style="padding: 8px; margin-top: 1em; background-color: red; color: white;">1/1 test cases complete.
+ <strong>1</strong> passes and <strong>1</strong> fails.</div>
+ </div>
+ ...and if it passes like this...
+ <div class="demo">
+ <h1>testoflogging</h1>
+ <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
+ <strong>2</strong> passes and <strong>0</strong> fails.</div>
+ </div>
+ And if you get this...
+ <div class="demo">
+ <b>Fatal error</b>: Failed opening required '../classes/log.php' (include_path='') in <b>/home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php</b> on line <b>7</b>
+ </div>
+ it means you're missing the <em>classes/Log.php</em> file that could look like...
+<pre>
+&lt;?php
+class Log {
+
+ function Log($file_path) {
+ }
+
+ function message() {
+ }
+}
+?&gt;;
+</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>
+&lt;?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-&gt;assertFalse(file_exists('/temp/test.log'));
+ $log-&gt;message('Should write this to a file');
+ $this-&gt;assertTrue(file_exists('/temp/test.log'));<strong>
+ }
+}
+?&gt;</strong>
+</pre>
+ Next we create a new file called <em>tests/all_tests.php</em>
+ and insert the following code...
+<pre>
+<strong>&lt;?php
+require_once('simpletest/unit_tester.php');
+require_once('simpletest/reporter.php');
+
+$test = &amp;new GroupTest('All tests');
+$test-&gt;addTestFile('log_test.php');
+$test-&gt;run(new HtmlReporter());
+?&gt;</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-&gt;_log-&gt;message("User $username logged in.");
+ ...
+ }
+ ...
+}
+</strong>
+</pre>
+ In the spirit of reuse we are using our
+ <span class="new_code">Log</span> class.
+ A conventional test case might look like this...
+<pre>
+<strong>
+&lt;?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 = &amp;new SessionPool($log);
+ $session_pool-&gt;logIn('fred');
+ $messages = file('/temp/test.log');
+ $this-&gt;assertEqual($messages[0], "User fred logged in.\n");
+ }
+}
+?&gt;</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>
+&lt;?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 = &amp;new MockLog($this);
+ $log-&gt;expectOnce('message', array('User fred logged in.'));</strong>
+ $session_pool = &amp;new SessionPool($log);
+ $session_pool-&gt;logIn('fred');<strong>
+ $log-&gt;tally();</strong>
+ }
+}
+?&gt;
+</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>
+&lt;?php<strong>
+require_once('simpletest/web_tester.php');</strong>
+require_once('simpletest/reporter.php');
+<strong>
+class TestOfAbout extends WebTestCase {
+
+ function setUp() {
+ $this-&gt;get('http://test-server/index.php');
+ $this-&gt;clickLink('About');
+ }
+
+ function testSearchEngineOptimisations() {
+ $this-&gt;assertTitle('A long title about us for search engines');
+ $this-&gt;assertWantedPattern('/a popular keyphrase/i');
+ }
+}</strong>
+$test = &amp;new TestOfAbout();
+$test-&gt;run(new HtmlReporter());
+?&gt;
+</pre>
+ With this code as an acceptance test you can ensure that
+ the content always meets the specifications of both the
+ developers and the other project stakeholders.
+ </p>
+ <p>
+ <a href="http://sourceforge.net/projects/simpletest/"><img src="http://sourceforge.net/sflogo.php?group_id=76550&amp;type=5" width="210" height="62" border="0" alt="SourceForge.net Logo"></a>
+ </p>
+
+ </div>
+<div class="copyright">
+ Copyright<br>Marcus Baker, Jason Sweat, Perrick Penet 2004
+ </div>
+</body>
+</html>