diff options
Diffstat (limited to 'vendors/simpletest/docs/en/index.html')
-rw-r--r-- | vendors/simpletest/docs/en/index.html | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/vendors/simpletest/docs/en/index.html b/vendors/simpletest/docs/en/index.html new file mode 100644 index 000000000..03b6c5cef --- /dev/null +++ b/vendors/simpletest/docs/en/index.html @@ -0,0 +1,538 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title> + Download the Simple Test testing framework - + Unit tests and mock objects for PHP + </title> +<link rel="stylesheet" type="text/css" href="docs.css" title="Styles"> +</head> +<body> +<div class="menu_back"><div class="menu"> +<span class="chosen">SimpleTest</span> + | + <a href="overview.html">Overview</a> + | + <a href="unit_test_documentation.html">Unit tester</a> + | + <a href="group_test_documentation.html">Group tests</a> + | + <a href="mock_objects_documentation.html">Mock objects</a> + | + <a href="partial_mocks_documentation.html">Partial mocks</a> + | + <a href="reporter_documentation.html">Reporting</a> + | + <a href="expectation_documentation.html">Expectations</a> + | + <a href="web_tester_documentation.html">Web tester</a> + | + <a href="form_testing_documentation.html">Testing forms</a> + | + <a href="authentication_documentation.html">Authentication</a> + | + <a href="browser_documentation.html">Scriptable browser</a> +</div></div> +<h1>Simple Test for PHP</h1> + This page... + <ul> +<li> + <a href="#unit">Using unit tester</a> + with an example. + </li> +<li> + <a href="#group">Grouping tests</a> + for testing with one click. + </li> +<li> + <a href="#mock">Using mock objects</a> + to ease testing and gain tighter control. + </li> +<li> + <a href="#web">Testing web pages</a> + at the browser level. + </li> +</ul> +<div class="content"> + + + <p> + The following assumes that you are familiar with the concept + of unit testing as well as the PHP web development language. + It is a guide for the impatient new user of + <a href="https://sourceforge.net/project/showfiles.php?group_id=76550">SimpleTest</a>. + For fuller documentation, especially if you are new + to unit testing see the ongoing + <a href="unit_test_documentation.html">documentation</a>, and for + example test cases see the + <a href="http://www.lastcraft.com/first_test_tutorial.php">unit testing tutorial</a>. + </p> + + <p><a class="target" name="unit"><h2>Using the tester quickly</h2></a></p> + <p> + Amongst software testing tools, a unit tester is the one + closest to the developer. + In the context of agile development the test code sits right + next to the source code as both are written simultaneously. + In this context SimpleTest aims to be a complete PHP developer + test solution and is called "Simple" because it + should be easy to use and extend. + It wasn't a good choice of name really. + It includes all of the typical functions you would expect from + <a href="http://www.junit.org/">JUnit</a> and the + <a href="http://sourceforge.net/projects/phpunit/">PHPUnit</a> + ports, and includes + <a href="http://www.mockobjects.com">mock objects</a>. + </p> + <p> + What makes this tool immediately useful to the PHP developer is the internal + web browser. + This allows tests that navigate web sites, fill in forms and test pages. + Being able to write these test in PHP means that it is easy to write + integrated tests. + An example might be confirming that a user was written to a database + after a signing up through the web site. + </p> + <p> + The quickest way to demonstrate SimpleTest is with an example. + </p> + <p> + Let us suppose we are testing a simple file logging class called + <span class="new_code">Log</span> in <em>classes/log.php</em>. + We start by creating a test script which we will call + <em>tests/log_test.php</em> and populate it as follows... +<pre> +<?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> |