Browse files

Building the version 1

  • Loading branch information...
1 parent 6391221 commit 5f796eb3670b2a6905c251087e3c6292a7bb5ced lastcraft committed Feb 26, 2005
View
223 tutorials/SimpleTest/Expectations.pkg
@@ -4,15 +4,15 @@
<refname>Expectations</refname>
<refpurpose/>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id mock}">
<title>More control over mock objects</title>
<para>
The default behaviour of the
- <a href="mock_objects_documentation.html">mock objects</a>
+ {@link mock objects.html mock objects}
in
- <a href="http://sourceforge.net/projects/simpletest/">SimpleTest</a>
+ {@link http://sourceforge.net/projects/simpletest/ SimpleTest}
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.
@@ -29,41 +29,41 @@
</para>
<para>
For example, suppose we have a news service that has failed
- to connect to it's remote source.
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class NewsService {
+ to connect to its remote source.
+<programlisting role="php">
+class NewsService {
...
- function publish(&$writer) {
- if (! $this->isConnected()) {
- $writer->write('Cannot connect to news service "' .
- $this->_name . '" at this time. ' .
+ function publish(&amp;$writer) {
+ if (! $this-&gt;isConnected()) {
+ $writer-&gt;write('Cannot connect to news service "' .
+ $this-&gt;_name . '" at this time. ' .
'Please try again later.');
}
...
}
-}]]><![CDATA[
-]]></program-listing>
- Here it is sending it's content to a
+}
+</programlisting>
+ 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...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TestOfNewsService extends UnitTestCase {
...
- function testConnectionFailure() {]]><![CDATA[
- $writer = &new MockWriter($this);
- $writer->expectOnce('write', array(
+ function testConnectionFailure() {
+ $writer = &amp;new MockWriter($this);
+ $writer-&gt;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);
+ $service = &amp;new NewsService('BBC News');
+ $service-&gt;publish($writer);
- $writer->tally();]]><![CDATA[
+ $writer-&gt;tally();
}
}
-]]></program-listing>
+</programlisting>
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
@@ -74,22 +74,22 @@ class TestOfNewsService extends UnitTestCase {
To get around this, we would like to do a regular expression
test rather than an exact match.
We can actually do this with...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TestOfNewsService extends UnitTestCase {
...
function testConnectionFailure() {
- $writer = &new MockWriter($this);]]><![CDATA[
- $writer->expectOnce(
+ $writer = &amp;new MockWriter($this);
+ $writer-&gt;expectOnce(
'write',
- array(new WantedPatternExpectation('/cannot connect/i')));]]><![CDATA[
+ array(new WantedPatternExpectation('/cannot connect/i')));
- $service = &new NewsService('BBC News');
- $service->publish($writer);
+ $service = &amp;new NewsService('BBC News');
+ $service-&gt;publish($writer);
- $writer->tally();
+ $writer-&gt;tally();
}
}
-]]></program-listing>
+</programlisting>
Instead of passing in the expected parameter to the
<span class="new_code">MockWriter</span> we pass an
expectation class called
@@ -102,7 +102,7 @@ class TestOfNewsService extends UnitTestCase {
</para>
<para>
The <span class="new_code">WantedPatternExpectation</span> takes
- the regular expression to match in it's constructor.
+ 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.
@@ -113,63 +113,65 @@ class TestOfNewsService extends UnitTestCase {
</para>
<para>
The possible expectation classes are...
- <table>
- <tr>
-<td>
+ <table frame="all" id="{@id features}}">
+<tbody>
+ <row>
+<entry>
<span class="new_code">EqualExpectation</span>
-</td>
-<td>An equality, rather than the stronger identity comparison</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>An equality, rather than the stronger identity comparison</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">NotEqualExpectation</span>
-</td>
-<td>An inequality comparison</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>An inequality comparison</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">IndenticalExpectation</span>
-</td>
-<td>The default mock object check which must match exactly</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>The default mock object check which must match exactly</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">NotIndenticalExpectation</span>
-</td>
-<td>Inverts the mock object logic</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>Inverts the mock object logic</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">WantedPatternExpectation</span>
-</td>
-<td>Uses a Perl Regex to match a string</td>
-</tr>
- <tr>
-<td>
-<span class="new_code">NoUnwantedExpectation</span>
-</td>
-<td>Passes only if failing a Perl Regex</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>Uses a Perl Regex to match a string</entry>
+</row>
+ <row>
+<entry>
+<span class="new_code">NoUnwantedPatternExpectation</span>
+</entry>
+<entry>Passes only if failing a Perl Regex</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">IsAExpectation</span>
-</td>
-<td>Checks the type or class name only</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>Checks the type or class name only</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">NotAExpectation</span>
-</td>
-<td>Opposite of the <span class="new_code">IsAExpectation</span>
-</td>
-</tr>
- <tr>
-<td>
+</entry>
+<entry>Opposite of the <span class="new_code">IsAExpectation</span>
+</entry>
+</row>
+ <row>
+<entry>
<span class="new_code">MethodExistsExpectation</span>
-</td>
-<td>Checks a method is available on an object</td>
-</tr>
- </table>
+</entry>
+<entry>Checks a method is available on an object</entry>
+</row>
+ </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
@@ -182,26 +184,26 @@ class TestOfNewsService extends UnitTestCase {
The expectation classes can be used not just for sending assertions
from mock objects, but also for selecting behaviour for either
the
- <a href="mock_objects_documentation.html">mock objects</a>
+ {@link mock objects.html mock objects}
or the
- <a href="server_stubs_documentation.html">server stubs</a>.
+ {@link server stubs.html server stubs}.
Anywhere a list of arguments is given, a list of expectation objects
can be inserted instead.
</para>
<para>
Suppose we want an authorisation server stub to simulate a successful login
only if it receives a valid session object.
We can do this as follows...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
Stub::generate('Authorisation');
-]]><![CDATA[
+
$authorisation = new StubAuthorisation();
-$authorisation->setReturnValue(
+$authorisation-&gt;setReturnValue(
'isAllowed',
true,
array(new IsAExpectation('Session', 'Must be a session')));
-$authorisation->setReturnValue('isAllowed', false);]]><![CDATA[
-]]></program-listing>
+$authorisation-&gt;setReturnValue('isAllowed', false);
+</programlisting>
We have set the default stub behaviour to return false when
<span class="new_code">isAllowed</span> is called.
When we call the method with a single parameter that
@@ -229,11 +231,8 @@ $authorisation->setReturnValue('isAllowed', false);]]><![CDATA[
In order to work correctly with the stubs and mocks the new
expectation class should extend
<span class="new_code">SimpleExpectation</span>...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class ValidIp extends SimpleExpectation {
- function ValidIp() {
- $this->SimpleExpectation();
- }
+<programlisting role="php">
+class ValidIp extends SimpleExpectation {
function test($ip) {
return (ip2long($ip) != -1);
@@ -242,8 +241,8 @@ $authorisation->setReturnValue('isAllowed', false);]]><![CDATA[
function testMessage($ip) {
return "Address [$ip] should be a valid IP address";
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
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
@@ -260,28 +259,28 @@ $authorisation->setReturnValue('isAllowed', false);]]><![CDATA[
<refsect1 id="{@id unit}">
<title>Under the bonnet of the unit tester</title>
<para>
- The <a href="http://sourceforge.net/projects/simpletest/">SimpleTest unit testing framework</a>
+ The {@link http://sourceforge.net/projects/simpletest/ SimpleTest unit testing framework}
also uses the expectation classes internally for the
- <a href="unit_test_documentation.html">UnitTestCase class</a>.
+ {@link UnitTestCase class.html UnitTestCase class}.
We can also take advantage of these mechanisms to reuse our
homebrew expectation classes within the test suites directly.
</para>
<para>
The most crude way of doing this is to use the
<span class="new_code">SimpleTest::assertExpectation()</span> method to
test against it directly...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class TestOfNetworking extends UnitTestCase {
+<programlisting role="php">
+class TestOfNetworking extends UnitTestCase {
...
function testGetValidIp() {
- $server = &new Server();
- $this->assertExpectation(
+ $server = &amp;new Server();
+ $this-&gt;assertExpectation(
new ValidIp(),
- $server->getIp(),
- 'Server IP address->%s');
+ $server-&gt;getIp(),
+ 'Server IP address-&gt;%s');
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
This is a little untidy compared with our usual
<span class="new_code">assert...()</span> syntax.
</para>
@@ -292,21 +291,21 @@ $authorisation->setReturnValue('isAllowed', false);]]><![CDATA[
If we pretend that our expectation is a little more
complicated for a moment, so that we want to reuse it,
we get...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TestOfNetworking extends UnitTestCase {
- ...]]><![CDATA[
+ ...
function assertValidIp($ip, $message = '%s') {
- $this->assertExpectation(new ValidIp(), $ip, $message);
- }]]><![CDATA[
+ $this-&gt;assertExpectation(new ValidIp(), $ip, $message);
+ }
function testGetValidIp() {
- $server = &new Server();]]><![CDATA[
- $this->assertValidIp(
- $server->getIp(),
- 'Server IP address->%s');]]><![CDATA[
+ $server = &amp;new Server();
+ $this-&gt;assertValidIp(
+ $server-&gt;getIp(),
+ 'Server IP address-&gt;%s');
}
}
-]]></program-listing>
+</programlisting>
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
View
87 tutorials/SimpleTest/FormTesting.pkg
@@ -4,7 +4,7 @@
<refname>Testing forms</refname>
<refpurpose/>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id submit}">
<title>Submitting a simple form</title>
@@ -32,20 +32,17 @@
</para>
<para>
We can navigate to this code, via the
- <a href="http://www.lastcraft.com/form_testing_documentation.php">LastCraft</a>
+ {@link http://www.lastcraft.com/form_testing_documentation.php LastCraft}
site, with the following test...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class SimpleFormTests extends WebTestCase {
- function SimpleFormTests() {
- $this->WebTestCase();
- }]]><![CDATA[
function testDefaultValue() {
- $this->get('http://www.lastcraft.com/form_testing_documentation.php');
- $this->assertField('a', 'A default');
- }]]><![CDATA[
+ $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
+ $this-&gt;assertField('a', 'A default');
+ }
}
-]]></program-listing>
+</programlisting>
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
@@ -55,20 +52,17 @@ class SimpleFormTests extends WebTestCase {
<para>
We could submit the form straight away, but first we'll change
the value of the text field and only then submit it...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class SimpleFormTests extends WebTestCase {
- function SimpleFormTests() {
- $this->WebTestCase();
- }
-
+
function testDefaultValue() {
- $this->get('http://www.my-site.com/');
- $this->assertField('a', 'A default');]]><![CDATA[
- $this->setField('a', 'New value');
- $this->clickSubmit('Go');]]><![CDATA[
+ $this-&gt;get('http://www.my-site.com/');
+ $this-&gt;assertField('a', 'A default');
+ $this-&gt;setField('a', 'New value');
+ $this-&gt;clickSubmit('Go');
}
}
-]]></program-listing>
+</programlisting>
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>
@@ -78,7 +72,7 @@ class SimpleFormTests extends WebTestCase {
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.
+ {@link http://www.w3.org/People/Raggett/tidy/ HTMLTidy} should be used.
</para>
<para>
If a field is not present in any form, or if an option is unavailable,
@@ -108,18 +102,15 @@ class SimpleFormTests extends WebTestCase {
</para>
<para>
The following test will confirm it...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class SimpleFormTests extends WebTestCase {
- function SimpleFormTests() {
- $this->WebTestCase();
- }
-
- function testNoSuperuserChoiceAvailable() {]]><![CDATA[
- $this->get('http://www.lastcraft.com/form_testing_documentation.php');
- $this->assertFalse($this->setField('type', 'Superuser'));]]><![CDATA[
+ ...
+ function testNoSuperuserChoiceAvailable() {
+ $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
+ $this-&gt;assertFalse($this-&gt;setField('type', 'Superuser'));
}
}
-]]></program-listing>
+</programlisting>
The selection will not be changed on a failure to set
a widget value.
</para>
@@ -185,20 +176,17 @@ class SimpleFormTests extends WebTestCase {
<para>
If we wish to disable all but the retrieval privileges and
submit this information we can do it like this...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class SimpleFormTests extends WebTestCase {
- function SimpleFormTests() {
- $this->WebTestCase();
- }]]><![CDATA[
-
+ ...
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->clickSubmit('Enable Privileges');
- }]]><![CDATA[
+ $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
+ $this-&gt;assertField('crud', array('c', 'r', 'u', 'd'));
+ $this-&gt;setField('crud', array('r'));
+ $this-&gt;clickSubmit('Enable Privileges');
+ }
}
-]]></program-listing>
+</programlisting>
Instead of setting the field to a single value, we give it a list
of values.
We do the same when testing expected values.
@@ -212,20 +200,17 @@ class SimpleFormTests extends WebTestCase {
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.
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class SimpleFormTests extends WebTestCase {
- function SimpleFormTests() {
- $this->WebTestCase();
- }]]><![CDATA[
-
+ ...
function testAttemptedHack() {
- $this->post(
+ $this-&gt;post(
'http://www.my-site.com/add_user.php',
- array('type' => 'superuser'));
- $this->assertNoUnwantedPattern('/user created/i');
- }]]><![CDATA[
+ array('type' =&gt; 'superuser'));
+ $this-&gt;assertNoUnwantedPattern('/user created/i');
+ }
}
-]]></program-listing>
+</programlisting>
By adding data to the <span class="new_code">WebTestCase::post()</span>
method, we are attempting to fetch the page as a form submission.
</para>
View
228 tutorials/SimpleTest/GroupTests.pkg
@@ -4,15 +4,15 @@
<refname>Group tests</refname>
<refpurpose/>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id group}">
<title>Grouping tests</title>
<para>
To run test cases as part of a group the test cases should really
be placed in files without the runner code...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[<?php
+<programlisting role="php">
+&lt;?php
require_once('../classes/io.php');
class FileTester extends UnitTestCase {
@@ -22,23 +22,23 @@
class SocketTester extends UnitTestCase {
...
}
-?>]]><![CDATA[
-]]></program-listing>
+?&gt;
+</programlisting>
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.
</para>
<para>
If you have extended any test cases, you can include them
as well.
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('../classes/io.php');
-]]><![CDATA[
+
class MyFileTestCase extends UnitTestCase {
...
}
- SimpleTestOptions::ignore('MyFileTestCase');]]><![CDATA[
+ SimpleTestOptions::ignore('MyFileTestCase');
class FileTester extends MyFileTestCase {
...
@@ -47,10 +47,10 @@
class SocketTester extends UnitTestCase {
...
}
-?>
-]]></program-listing>
+?&gt;
+</programlisting>
The <span class="new_code">FileTester</span> class does
- no contain any actual tests, but is a base class for other
+ 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
@@ -63,48 +63,48 @@
Next we create a group test file, called say <em>group_test.php</em>.
You will think of a better name I am sure.
We will add the test file using a safe method...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
- require_once('simpletest/reporter.php');]]><![CDATA[
+ require_once('simpletest/reporter.php');
require_once('file_test.php');
- $test = &new GroupTest('All file tests');
- $test->addTestCase(new FileTestCase());
- $test->run(new HtmlReporter());]]><![CDATA[
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('All file tests');
+ $test-&gt;addTestCase(new FileTestCase());
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
This instantiates the test case before the test suite is
run.
This could get a little expensive with a large number of test
cases, so another method is provided that will only
instantiate the class when it is needed...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
require_once('file_test.php');
- $test = &new GroupTest('All file tests');]]><![CDATA[
- $test->addTestClass('FileTestCase');]]><![CDATA[
- $test->run(new HtmlReporter());
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('All file tests');
+ $test-&gt;addTestClass('FileTestCase');
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
The problem with this method 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.
We can save a lot of typing with...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
- $test = &new GroupTest('All file tests');]]><![CDATA[
- $test->addTestFile('file_test.php');]]><![CDATA[
- $test->run(new HtmlReporter());
-?&gt;
-]]></program-listing>
+ $test = &amp;new GroupTest('All file tests');
+ $test-&gt;addTestFile('file_test.php');
+ $test-&gt;run(new HtmlReporter());
+?&amp;gt;
+</programlisting>
What happens here is that the <span class="new_code">GroupTest</span>
class has done the <span class="new_code">require_once()</span>
for us.
@@ -123,7 +123,7 @@
and no others.
</li>
<li>
- New test case extension classes thet get included will be
+ 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
@@ -143,83 +143,91 @@
<para>
To get a more flexible group test we can subclass
<span class="new_code">GroupTest</span> and then instantiate it as needed...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
- ]]><![CDATA[
+
class FileGroupTest extends GroupTest {
function FileGroupTest() {
- $this->GroupTest('All file tests');
- $this->addTestFile('file_test.php');
+ $this-&gt;GroupTest('All file tests');
+ $this-&gt;addTestFile('file_test.php');
}
- }]]><![CDATA[
-?>
-]]></program-listing>
+ }
+?&gt;
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('file_group_test.php');
- ]]><![CDATA[
- $test = &new FileGroupTest();
- $test->run(new HtmlReporter());]]><![CDATA[
-?>
-]]></program-listing>
+
+ $test = &amp;new FileGroupTest();
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
...or we can group them into even larger group tests...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('file_group_test.php');
- ]]><![CDATA[
- $test = &new BigGroupTest('Big group');
- $test->addTestCase(new FileGroupTest());
- $test->addTestCase(...);
- $test->run(new HtmlReporter());]]><![CDATA[
-?>
-]]></program-listing>
+
+ $test = &amp;new BigGroupTest('Big group');
+ $test-&gt;addTestCase(new FileGroupTest());
+ $test-&gt;addTestCase(...);
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
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.
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
class FileGroupTest extends GroupTest {
function FileGroupTest() {
- $this->GroupTest('All file tests');
- $test->addTestFile('file_test.php');
+ $this-&gt;GroupTest('All file tests');
+ $test-&gt;addTestFile('file_test.php');
}
}
- ]]><![CDATA[
+
if (! defined('RUNNER')) {
- define('RUNNER', true);]]><![CDATA[
- $test = &new FileGroupTest();
- $test->run(new HtmlReporter());
+ define('RUNNER', true);
+ $test = &amp;new FileGroupTest();
+ $test-&gt;run(new HtmlReporter());
}
-?>
-]]></program-listing>
+?&gt;
+</programlisting>
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.
-<program-listing role="php"><![CDATA[
-<?php
- define('RUNNER', true);</strong>
- ]]><![CDATA[
+<programlisting role="php">
+&lt;?php
+ define('RUNNER', true);
require_once('file_group_test.php');
- ]]><![CDATA[
- ]]><![CDATA[
- require_once('file_group_test.php');
- ]]><![CDATA[
- $test = &new BigGroupTest('Big group');
- $test->addTestCase(new FileGroupTest());
- $test->addTestCase(...);
- $test->run(new HtmlReporter());
-?>
-]]></program-listing>
+
+ $test = &amp;new BigGroupTest('Big group');
+ $test-&gt;addTestCase(new FileGroupTest());
+ $test-&gt;addTestCase(...);
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
+ As with the normal test cases, a <span class="new_code">GroupTest</span> can
+ be loaded with the <span class="new_code">GroupTest::addTestFile()</span> method.
+<programlisting role="php">
+&lt;?php
+ define('RUNNER', true);
+
+ $test = &amp;new BigGroupTest('Big group');
+ $test-&gt;addTestFile('file_group_test.php');
+ $test-&gt;addTestFile(...);
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
</para>
</refsect1>
<refsect1 id="{@id legacy}">
@@ -233,48 +241,48 @@
</para>
<para>
Say we have the following
- <a href="http://sourceforge.net/projects/phpunit">PhpUnit</a>
+ {@link http://sourceforge.net/projects/phpunit PhpUnit}
test case in the file <em>config_test.php</em>...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class ConfigFileTest extends TestCase {
+<programlisting role="php">
+class ConfigFileTest extends TestCase {
function ConfigFileTest() {
- $this->TestCase('Config file test');
+ $this-&gt;TestCase('Config file test');
}
function testContents() {
$config = new ConfigFile('test.conf');
- $this->assertRegexp('/me/', $config->getValue('username'));
+ $this-&gt;assertRegexp('/me/', $config-&gt;getValue('username'));
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
The group test can recognise this as long as we include
the appropriate adapter class before we add the test
file...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
- require_once('simpletest/reporter.php');]]><![CDATA[
- require_once('simpletest/adapters/phpunit_test_case.php');]]><![CDATA[
+ require_once('simpletest/reporter.php');
+ require_once('simpletest/adapters/phpunit_test_case.php');
- $test = &new GroupTest('All file tests');]]><![CDATA[
- $test->addTestFile('config_test.php');]]><![CDATA[
- $test->run(new HtmlReporter());
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('All file tests');
+ $test-&gt;addTestFile('config_test.php');
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
There are only two adapters, the other is for the
- <a href="http://pear.php.net/manual/en/package.php.phpunit.php">PEAR</a>
- unit tester...
-<program-listing role="php"><![CDATA[
-<?php
+ {@link http://pear.php.net/manual/en/package.php.phpunit.php PEAR}
+ 1.0 unit tester...
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
- require_once('simpletest/reporter.php');]]><![CDATA[
- require_once('simpletest/adapters/pear_test_case.php');]]><![CDATA[
+ require_once('simpletest/reporter.php');
+ require_once('simpletest/adapters/pear_test_case.php');
- $test = &new GroupTest('All file tests');]]><![CDATA[
- $test->addTestFile('some_pear_test_cases.php');]]><![CDATA[
- $test->run(new HtmlReporter());
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('All file tests');
+ $test-&gt;addTestFile('some_pear_test_cases.php');
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
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
View
316 tutorials/SimpleTest/MockObjects.pkg
@@ -4,7 +4,7 @@
<refname>Mock objects</refname>
<refpurpose/>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id what}">
<title>What are mock objects?</title>
@@ -27,7 +27,7 @@
</para>
<para>
If mock objects only behaved as actors they would simply be
- known as <a href="server_stubs_documentation.html">server stubs</a>.
+ known as {@link server stubs.html server stubs}.
</para>
<para>
However, the mock objects not only play a part (by supplying chosen
@@ -50,8 +50,8 @@
<para>
In the same way that we create server stubs, all we need is an
existing class, say a database connection that looks like this...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class DatabaseConnection {
+<programlisting role="php">
+class DatabaseConnection {
function DatabaseConnection() {
}
@@ -60,42 +60,39 @@
function selectQuery() {
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[require_once('simpletest/unit_tester.php');
+<programlisting role="php">
+require_once('simpletest/unit_tester.php');
require_once('simpletest/mock_objects.php');
require_once('database_connection.php');
-Mock::generate('DatabaseConnection');]]><![CDATA[
-]]></program-listing>
+Mock::generate('DatabaseConnection');
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
require_once('simpletest/unit_tester.php');
require_once('simpletest/mock_objects.php');
require_once('database_connection.php');
Mock::generate('DatabaseConnection');
-]]><![CDATA[
+
class MyTestCase extends UnitTestCase {
- function MyTestCase() {
- $this->UnitTestCase('My test');
- }
function testSomething() {
- $connection = &new MockDatabaseConnection($this);
+ $connection = &amp;new MockDatabaseConnection($this);
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
Unlike the generated stubs the mock constructor needs a reference
to the test case so that it can dispatch passes and failures while
- checking it's expectations.
+ 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.
@@ -109,19 +106,19 @@ class MyTestCase extends UnitTestCase {
<span class="new_code">$connection-&gt;query()</span> are still
legal.
As with stubs we can replace the default null return values...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[$connection->setReturnValue('query', 37);]]><![CDATA[
-]]></program-listing>
+<programlisting role="php">
+$connection-&gt;setReturnValue('query', 37);
+</programlisting>
Now every time we call
<span class="new_code">$connection-&gt;query()</span> we get
the result of 37.
As with the stubs we can set wildcards and we can overload the
wildcard parameter.
We can also add extra methods to the mock when generating it
and choose our own class name...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));]]><![CDATA[
-]]></program-listing>
+<programlisting role="php">
+Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));
+</programlisting>
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>
@@ -131,35 +128,32 @@ class MyTestCase extends UnitTestCase {
<para>
All of the patterns available with server stubs are available
to mock objects...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class Iterator {
function Iterator() {
}
function next() {
}
}
-]]></program-listing>
+</programlisting>
Again, assuming that this iterator only returns text until it
reaches the end, when it returns false, we can simulate it
with...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
Mock::generate('Iterator');
class IteratorTest extends UnitTestCase() {
- function IteratorTest() {
- $this->UnitTestCase();
- }
- function testASequence() {]]><![CDATA[
- $iterator = &new MockIterator($this);
- $iterator->setReturnValue('next', false);
- $iterator->setReturnValueAt(0, 'next', 'First string');
- $iterator->setReturnValueAt(1, 'next', 'Second string');]]><![CDATA[
+ function testASequence() {
+ $iterator = &amp;new MockIterator($this);
+ $iterator-&gt;setReturnValue('next', false);
+ $iterator-&gt;setReturnValueAt(0, 'next', 'First string');
+ $iterator-&gt;setReturnValueAt(1, 'next', 'Second string');
...
}
}
-]]></program-listing>
+</programlisting>
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
@@ -171,15 +165,15 @@ class IteratorTest extends UnitTestCase() {
</para>
<para>
A repeat of the stubbed information holder with name/value pairs...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class Configuration {
function Configuration() {
}
function getValue($key) {
}
}
-]]></program-listing>
+</programlisting>
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
@@ -188,32 +182,32 @@ class Configuration {
<span class="new_code">getValue()</span> method and yet
we want different results for different keys.
Luckily the mocks have a filter system...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[$config = &new MockConfiguration($this);
-$config->setReturnValue('getValue', 'primary', array('db_host'));
-$config->setReturnValue('getValue', 'admin', array('db_user'));
-$config->setReturnValue('getValue', 'secret', array('db_password'));]]><![CDATA[
-]]></program-listing>
+<programlisting role="php">
+$config = &amp;new MockConfiguration($this);
+$config-&gt;setReturnValue('getValue', 'primary', array('db_host'));
+$config-&gt;setReturnValue('getValue', 'admin', array('db_user'));
+$config-&gt;setReturnValue('getValue', 'secret', array('db_password'));
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
-$config->getValue('db_user')
-]]></program-listing>
+<programlisting role="php">
+$config-&gt;getValue('db_user')
+</programlisting>
...it will return "admin".
It finds this by attempting to match the calling arguments
- to it's list of returns one after another until
+ to its list of returns one after another until
a complete match is found.
</para>
<para>
There are times when you want a specific object to be
dished out by the mock rather than a copy.
Again this is identical to the server stubs mechanism...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class Thing {
}
@@ -224,14 +218,14 @@ class Vector {
function get($index) {
}
}
-]]></program-listing>
+</programlisting>
In this case you can set a reference into the mock's
return list...
-<program-listing role="php"><![CDATA[
-$thing = new Thing();]]><![CDATA[
-$vector = &new MockVector($this);
-$vector->setReturnReference('get', $thing, array(12));]]><![CDATA[
-]]></program-listing>
+<programlisting role="php">
+$thing = new Thing();
+$vector = &amp;new MockVector($this);
+$vector-&gt;setReturnReference('get', $thing, array(12));
+</programlisting>
With this arrangement you know that every time
<span class="new_code">$vector-&gt;get(12)</span> is
called it will return the same
@@ -255,24 +249,24 @@ $vector->setReturnReference('get', $thing, array(12));]]><![CDATA[
complicated, we want to add this behaviour with a decorator (GOF).
The <span class="new_code">SessionPool</span> code currently looks
like this...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class SessionPool {
+<programlisting role="php">
+class SessionPool {
function SessionPool() {
...
}
- function &findSession($cookie) {
+ function &amp;findSession($cookie) {
...
}
...
}
class Session {
...
-}]]><![CDATA[
-</pre>
+}
+&lt;/php&gt;
While our logging code looks like this...
-<pre>]]><![CDATA[
+&lt;php&gt;
class Log {
function Log() {
...
@@ -284,16 +278,16 @@ class Log {
}
class LoggingSessionPool {
- function LoggingSessionPool(&$session_pool, &$log) {
+ function LoggingSessionPool(&amp;$session_pool, &amp;$log) {
...
}
- function &findSession(\$cookie) {
+ function &amp;findSession(\$cookie) {
...
}
...
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
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
@@ -329,29 +323,29 @@ class LoggingSessionPool {
</para>
<para>
Instead, here is the complete test method using mock object magic...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
Mock::generate('Session');
Mock::generate('SessionPool');
Mock::generate('Log');
class LoggingSessionPoolTest extends UnitTestCase {
...
- function testFindSessionLogging() {]]><![CDATA[
- $session = &new MockSession($this);
- $pool = &new MockSessionPool($this);
- $pool->setReturnReference('findSession', $session);
- $pool->expectOnce('findSession', array('abc'));
+ function testFindSessionLogging() {
+ $session = &amp;new MockSession($this);
+ $pool = &amp;new MockSessionPool($this);
+ $pool-&gt;setReturnReference('findSession', $session);
+ $pool-&gt;expectOnce('findSession', array('abc'));
- $log = &new MockLog($this);
- $log->expectOnce('message', array('Starting session abc'));
+ $log = &amp;new MockLog($this);
+ $log-&gt;expectOnce('message', array('Starting session abc'));
- $logging_pool = &new LoggingSessionPool($pool, $log);
- $this->assertReference($logging_pool->findSession('abc'), $session);
- $pool->tally();
- $log->tally();]]><![CDATA[
+ $logging_pool = &amp;new LoggingSessionPool($pool, $log);
+ $this-&gt;assertReference($logging_pool-&gt;findSession('abc'), $session);
+ $pool-&gt;tally();
+ $log-&gt;tally();
}
}
-]]></program-listing>
+</programlisting>
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.
@@ -360,7 +354,7 @@ class LoggingSessionPoolTest extends UnitTestCase {
</para>
<para>
<span class="new_code">findSession()</span> is a factory
- method the simulation of which is described <a href="#stub">above</a>.
+ method the simulation of which is described {@link #stub above}.
The point of departure comes with the first
<span class="new_code">expectOnce()</span> call.
This line states that whenever
@@ -417,62 +411,66 @@ class LoggingSessionPoolTest extends UnitTestCase {
</para>
<para>
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>
- <tr>
+ in {@link http://www.lastcraft.com/simple_test.php SimpleTest}...
+ <table frame="all" id="{@id features}}">
+<thead>
+ <row>
<th>Expectation</th>
<th>Needs <span class="new_code">tally()</span>
</th>
-</tr>
- <tr>
- <td>
+</row>
+ </thead>
+<tbody>
+<row>
+ <entry>
<span class="new_code">expectArguments($method, $args)</span>
-</td>
- <td style="text-align: center">No</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>No</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectArgumentsAt($timing, $method, $args)</span>
-</td>
- <td style="text-align: center">No</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>No</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectCallCount($method, $count)</span>
-</td>
- <td style="text-align: center">Yes</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>Yes</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectMaximumCallCount($method, $count)</span>
-</td>
- <td style="text-align: center">No</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>No</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectMinimumCallCount($method, $count)</span>
-</td>
- <td style="text-align: center">Yes</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>Yes</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectNever($method)</span>
-</td>
- <td style="text-align: center">No</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>No</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectOnce($method, $args)</span>
-</td>
- <td style="text-align: center">Yes</td>
- </tr>
- <tr>
- <td>
+</entry>
+ <entry>Yes</entry>
+ </row>
+ <row>
+ <entry>
<span class="new_code">expectAtLeastOnce($method, $args)</span>
-</td>
- <td style="text-align: center">Yes</td>
- </tr>
- </table>
+</entry>
+ <entry>Yes</entry>
+ </row>
+ </tbody>
+</table>
Where the parameters are...
<dl>
<dt class="new_code">$method</dt>
@@ -512,7 +510,7 @@ class LoggingSessionPoolTest extends UnitTestCase {
a file and dynamically generating them on the fly.
</para>
<para>
- Mock objects generated with <a href="simple_test.html">SimpleTest</a>
+ Mock objects generated with {@link SimpleTest.html SimpleTest}
are dynamic.
They are created at run time in memory, using
<span class="new_code">eval()</span>, rather than written
@@ -542,20 +540,20 @@ class LoggingSessionPoolTest extends UnitTestCase {
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...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/mock_objects.php');
require_once('../classes/connection.php');
-]]><![CDATA[
+
Mock::generate('Connection', 'BasicMockConnection');
class MockConnection extends BasicMockConnection {
- function MockConnection(&$test, $wildcard = '*') {
- $this->BasicMockConnection($test, $wildcard);
- $this->setReturn('query', false);
+ function MockConnection(&amp;$test, $wildcard = '*') {
+ $this-&gt;BasicMockConnection($test, $wildcard);
+ $this-&gt;setReturn('query', false);
}
- }]]><![CDATA[
-?>
-]]></program-listing>
+ }
+?&gt;
+</programlisting>
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>.
@@ -587,13 +585,13 @@ class LoggingSessionPoolTest extends UnitTestCase {
</para>
<para>
No, not at all.
- <a href="simple_test.html">SimpleTest</a> is a toolkit and one of those
+ {@link SimpleTest.html SimpleTest} is a toolkit and one of those
tools is the mock objects which can be employed independently.
Suppose you have your own favourite unit tester and all your current
test cases are written using it.
Pretend that you have called your unit tester PHPUnit (everyone else has)
and the core test class looks like this...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class PHPUnit {
function PHPUnit() {
}
@@ -602,15 +600,15 @@ class PHPUnit {
}
...
}
-]]></program-listing>
+</programlisting>
All the <span class="new_code">assertion()</span> method does
is print some fancy output and the boolean assertion parameter determines
whether to print a pass or a failure.
Let's say that it is used like this...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
$unit_test = new PHPUnit();
-$unit_test>assertion('I hope this file exists', file_exists('my_file'));
-]]></program-listing>
+$unit_test&gt;assertion('I hope this file exists', file_exists('my_file'));
+</programlisting>
How do you use mocks with this?
</para>
<para>
@@ -619,46 +617,46 @@ $unit_test>assertion('I hope this file exists', file_exists('my_file'));
<span class="new_code">_assertTrue()</span> and
by overriding this method we can use our own assertion format.
We start with a subclass, in say <em>my_mock.php</em>...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/mock_objects.php');
class MyMock extends SimpleMock() {
- function MyMock(&$test, $wildcard) {
- $this->SimpleMock($test, $wildcard);
+ function MyMock(&amp;$test, $wildcard) {
+ $this-&gt;SimpleMock($test, $wildcard);
}
function _assertTrue($assertion, $message) {
- $test = &$this->getTest();
- $test->assertion($message, $assertion);
+ $test = &amp;$this-&gt;getTest();
+ $test-&gt;assertion($message, $assertion);
}
}
-?>]]><![CDATA[
-]]></program-listing>
+?&gt;
+</programlisting>
Now instantiating <span class="new_code">MyMock</span> will create
an object that speaks the same language as your tester.
The catch is of course that we never create such an object, the
code generator does.
We need just one more line of code to tell the generator to use
your mock instead...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletst/mock_objects.php');
class MyMock extends SimpleMock() {
function MyMock($test, $wildcard) {
- $this->SimpleMock(&$test, $wildcard);
+ $this-&gt;SimpleMock(&amp;$test, $wildcard);
}
- function _assertTrue($assertion, $message , &$test) {
- $test->assertion($message, $assertion);
+ function _assertTrue($assertion, $message , &amp;$test) {
+ $test-&gt;assertion($message, $assertion);
}
- }]]><![CDATA[
- SimpleTestOptions::setMockBaseClass('MyMock');]]><![CDATA[
-?>
-]]></program-listing>
+ }
+ SimpleTestOptions::setMockBaseClass('MyMock');
+?&gt;
+</programlisting>
From now on you just include <em>my_mock.php</em> instead of the
- default <em>simple_mock.php</em> version and you can introduce
+ default <em>mock_objects.php</em> version and you can introduce
mock objects into your existing test suite.
</para>
</refsect1>
View
220 tutorials/SimpleTest/PartialMock.pkg
@@ -11,14 +11,14 @@
on more than one occasion and has saved a lot of work at that point.
</refpurpose>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id inject}">
<title>The mock injection problem</title>
<para>
When one object uses another it is very simple to just pass a mock
- version in already set up with it's expectations.
+ 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
@@ -28,22 +28,22 @@
</para>
<para>
For example, suppose we are building a telnet client and it
- needs to create a network socket to pass it's messages.
+ needs to create a network socket to pass its messages.
The connection method might look something like...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[<?php
+<programlisting role="php">
+&lt;?php
require_once('socket.php');
class Telnet {
...
- function &connect($ip, $port, $username, $password) {
- $socket = &new Socket($ip, $port);
- $socket->read( ... );
+ function &amp;connect($ip, $port, $username, $password) {
+ $socket = &amp;new Socket($ip, $port);
+ $socket-&gt;read( ... );
...
}
}
-?>]]><![CDATA[
-]]></program-listing>
+?&gt;
+</programlisting>
We would really like to have a mock object version of the socket
here, what can we do?
</para>
@@ -59,33 +59,33 @@
</para>
<para>
Here this would be...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('socket.php');
class Telnet {
...
- ]]><![CDATA[function &connect(&$socket, $username, $password) {
- $socket->read( ... );
+ function &amp;connect(&amp;$socket, $username, $password) {
+ $socket-&gt;read( ... );
...
- }]]><![CDATA[
+ }
}
-?>
-]]></program-listing>
+?&gt;
+</programlisting>
This means that the test code is typical for a test involving
mock objects.
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TelnetTest extends UnitTestCase {
...
- function testConnection() {]]><![CDATA[
- $socket = &new MockSocket($this);
+ function testConnection() {
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new Telnet();
+ $telnet-&gt;connect($socket, 'Me', 'Secret');
...
- $telnet = &new Telnet();
- $telnet->connect($socket, 'Me', 'Secret');
- ...]]><![CDATA[
}
}
-]]></program-listing>
+</programlisting>
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
@@ -95,82 +95,82 @@ class TelnetTest extends UnitTestCase {
<para>
The next simplest compromise is to have the created object passed
in as an optional parameter...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('socket.php');
class Telnet {
- ...]]><![CDATA[
- function &connect($ip, $port, $username, $password, $socket = false) {
+ ...
+ function &amp;connect($ip, $port, $username, $password, $socket = false) {
if (!$socket) {
- $socket = &new Socket($ip, $port);
+ $socket = &amp;new Socket($ip, $port);
}
- $socket->read( ... );]]><![CDATA[
+ $socket-&gt;read( ... );
...
return $socket;
}
}
-?>
-]]></program-listing>
+?&gt;
+</programlisting>
For a quick solution this is usually good enough.
The test now looks almost the same as if the parameter
was formally passed...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TelnetTest extends UnitTestCase {
...
- function testConnection() {]]><![CDATA[
- $socket = &new MockSocket($this);
+ function testConnection() {
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new Telnet();
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret', &amp;$socket);
...
- $telnet = &new Telnet();
- $telnet->connect('127.0.0.1', 21, 'Me', 'Secret', &$socket);
- ...]]><![CDATA[
}
}
-]]></program-listing>
- The problem with this approach is it's untidiness.
+</programlisting>
+ 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.
</para>
<para>
The next method is to pass in a factory object to do the creation...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('socket.php');
- class Telnet {]]><![CDATA[
- function Telnet(&$network) {
- $this->_network = &$network;
- }]]><![CDATA[
+ class Telnet {
+ function Telnet(&amp;$network) {
+ $this-&gt;_network = &amp;$network;
+ }
...
- function &connect($ip, $port, $username, $password) {]]><![CDATA[
- $socket = &$this->_network->createSocket($ip, $port);
- $socket->read( ... );]]><![CDATA[
+ function &amp;connect($ip, $port, $username, $password) {
+ $socket = &amp;$this-&gt;_network-&gt;createSocket($ip, $port);
+ $socket-&gt;read( ... );
...
return $socket;
}
}
-?>
-]]></program-listing>
+?&gt;
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TelnetTest extends UnitTestCase {
...
- function testConnection() {]]><![CDATA[
- $socket = &new MockSocket($this);
+ function testConnection() {
+ $socket = &amp;new MockSocket($this);
+ ...
+ $network = &amp;new MockNetwork($this);
+ $network-&gt;setReturnReference('createSocket', $socket);
+ $telnet = &amp;new Telnet($network);
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
...
- $network = &new MockNetwork($this);
- $network->setReturnReference('createSocket', $socket);
- $telnet = &new Telnet($network);
- $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
- ...]]><![CDATA[
}
}
-]]></program-listing>
+</programlisting>
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
@@ -187,44 +187,44 @@ class TelnetTest extends UnitTestCase {
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 it's own method...
-<program-listing role="php"><![CDATA[
-<?php
+ Firstly we move the socket creation into its own method...
+<programlisting role="php">
+&lt;?php
require_once('socket.php');
class Telnet {
...
- function &connect($ip, $port, $username, $password) {]]><![CDATA[
- $socket = &$this->_createSocket($ip, $port);]]><![CDATA[
- $socket->read( ... );
+ function &amp;connect($ip, $port, $username, $password) {
+ $socket = &amp;$this-&gt;_createSocket($ip, $port);
+ $socket-&gt;read( ... );
...
- }]]><![CDATA[
+ }
- function &_createSocket($ip, $port) {
+ function &amp;_createSocket($ip, $port) {
return new Socket($ip, $port);
- }]]><![CDATA[
+ }
}
-?>
-]]></program-listing>
+?&gt;
+</programlisting>
This is the only change we make to the application code.
</para>
<para>
For the test case we have to create a subclass so that
we can intercept the socket creation...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class TelnetTestVersion extends Telnet {
+<programlisting role="php">
+class TelnetTestVersion extends Telnet {
var $_mock;
- function TelnetTestVersion(&$mock) {
- $this->_mock = &$mock;
- $this->Telnet();
+ function TelnetTestVersion(&amp;$mock) {
+ $this-&gt;_mock = &amp;$mock;
+ $this-&gt;Telnet();
}
- function &_createSocket() {
- return $this->_mock;
+ function &amp;_createSocket() {
+ return $this-&gt;_mock;
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
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
@@ -238,18 +238,18 @@ class TelnetTest extends UnitTestCase {
After the completion of all of this extra work the
actual test case is fairly easy.
We just test our new class instead...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TelnetTest extends UnitTestCase {
...
- function testConnection() {]]><![CDATA[
- $socket = &new MockSocket($this);
+ function testConnection() {
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new TelnetTestVersion($socket);
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
...
- $telnet = &new TelnetTestVersion($socket);
- $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
- ...]]><![CDATA[
}
}
-]]></program-listing>
+</programlisting>
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
@@ -269,25 +269,25 @@ class TelnetTest extends UnitTestCase {
</para>
<para>
Here is the partial mock version of the test...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[Mock::generatePartial(
+<programlisting role="php">
+Mock::generatePartial(
'Telnet',
'TelnetTestVersion',
- array('_createSocket'));]]><![CDATA[
+ array('_createSocket'));
class TelnetTest extends UnitTestCase {
...
- function testConnection() {]]><![CDATA[
- $socket = &new MockSocket($this);
+ function testConnection() {
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new TelnetTestVersion($this);
+ $telnet-&gt;setReturnReference('_createSocket', $socket);
+ $telnet-&gt;Telnet();
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
...
- $telnet = &new TelnetTestVersion($this);
- $telnet->setReturnReference('_createSocket', $socket);
- $telnet->Telnet();
- $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
- ...]]><![CDATA[
}
}
-]]></program-listing>
+</programlisting>
The partial mock is a subclass of the original with
selected methods "knocked out" with test
versions.
@@ -307,7 +307,7 @@ class TelnetTest extends UnitTestCase {
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 it's normal parameters.
+ 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.
@@ -317,22 +317,22 @@ class TelnetTest extends UnitTestCase {
the same features as mock objects and all of the unmocked
methods behave as before.
We can set expectations very easily...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class TelnetTest extends UnitTestCase {
...
function testConnection() {
- $socket = &new MockSocket($this);
+ $socket = &amp;new MockSocket($this);
+ ...
+ $telnet = &amp;new TelnetTestVersion($this);
+ $telnet-&gt;setReturnReference('_createSocket', $socket);
+ $telnet-&gt;expectOnce('_createSocket', array('127.0.0.1', 21));
+ $telnet-&gt;Telnet();
+ $telnet-&gt;connect('127.0.0.1', 21, 'Me', 'Secret');
...
- $telnet = &new TelnetTestVersion($this);
- $telnet->setReturnReference('_createSocket', $socket);]]><![CDATA[
- $telnet->expectOnce('_createSocket', array('127.0.0.1', 21));]]><![CDATA[
- $telnet->Telnet();
- $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
- ...]]><![CDATA[
- $telnet->tally();]]><![CDATA[
+ $telnet-&gt;tally();
}
}
-]]></program-listing>
+</programlisting>
</para>
</refsect1>
<refsect1 id="{@id less}">
@@ -351,7 +351,7 @@ class TelnetTest extends UnitTestCase {
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 teh TemplateMethod pattern.
+ or for occasional testing of the TemplateMethod pattern.
</para>
<para>
It's all going to come down to the coding standards of your
View
142 tutorials/SimpleTest/Reporting.pkg
@@ -15,7 +15,7 @@
and there are other places to control the test run.
</refpurpose>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id html}">
@@ -45,9 +45,9 @@
For web page based displays there is the
<span class="new_code">HtmlReporter</span> class with the following
signature...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class HtmlReporter extends SimpleReporter {
- public HtmlReporter() { ... }
+ public HtmlReporter($encoding) { ... }
public makeDry(boolean $is_dry) { ... }
public void paintHeader(string $test_name) { ... }
public void sendNoCacheHeaders() { ... }
@@ -72,19 +72,27 @@ class HtmlReporter extends SimpleReporter {
public integer getTestCaseCount() { ... }
public integer getTestCaseProgress() { ... }
}
-]]></program-listing>
+</programlisting>
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()</span>
+ <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 passive receiver of test events.
+ 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 {@link http://www.php.net/manual/en/function.htmlentities.php html_entities()}
+ function.
</li>
<li>
<span class="new_code">void paintHeader(string $test_name)</span>
@@ -193,26 +201,23 @@ class HtmlReporter extends SimpleReporter {
</ul>
One simple modification is to get the HtmlReporter to display
the passes as well as the failures and errors...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class ShowPasses extends HtmlReporter {
- function ShowPasses() {
- $this->HtmlReporter();
- }
+<programlisting role="php">
+class ShowPasses extends HtmlReporter {
function paintPass($message) {
parent::paintPass($message);
- print "&<span class=\"pass\">Pass</span>: ";
- $breadcrumb = $this->getTestList();
+ print "&amp;&lt;span class=\"pass\"&gt;Pass&lt;/span&gt;: ";
+ $breadcrumb = $this-&gt;getTestList();
array_shift($breadcrumb);
- print implode("-&gt;", $breadcrumb);
- print "-&gt;$message<br />\n";
+ print implode("-&amp;gt;", $breadcrumb);
+ print "-&amp;gt;$message&lt;br /&gt;\n";
}
function _getCss() {
return parent::_getCss() . ' .pass { color: green; }';
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
</para>
<para>
One method that was glossed over was the <span class="new_code">makeDry()</span>
@@ -248,37 +253,34 @@ class HtmlReporter extends SimpleReporter {
<para>
A do nothing display, a blank canvas for your own creation, would
be...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[require_once('simpletest/simple_test.php');]]><![CDATA[
+<programlisting role="php">
+require_once('simpletest/simple_test.php');
-class MyDisplay extends SimpleReporter {]]><![CDATA[
- function MyDisplay() {
- $this->SimpleReporter();
- }]]><![CDATA[
+class MyDisplay extends SimpleReporter {
function paintHeader($test_name) {
}
function paintFooter($test_name) {
}
- function paintStart($test_name, $size) {]]><![CDATA[
- parent::paintStart($test_name, $size);]]><![CDATA[
+ function paintStart($test_name, $size) {
+ parent::paintStart($test_name, $size);
}
- function paintEnd($test_name, $size) {]]><![CDATA[
- parent::paintEnd($test_name, $size);]]><![CDATA[
+ function paintEnd($test_name, $size) {
+ parent::paintEnd($test_name, $size);
}
- function paintPass($message) {]]><![CDATA[
- parent::paintPass($message);]]><![CDATA[
+ function paintPass($message) {
+ parent::paintPass($message);
}
- function paintFail($message) {]]><![CDATA[
- parent::paintFail($message);]]><![CDATA[
+ function paintFail($message) {
+ parent::paintFail($message);
}
}
-]]></program-listing>
+</programlisting>
No output would come from this class until you add it.
</para>
</refsect1>
@@ -290,16 +292,16 @@ class MyDisplay extends SimpleReporter {]]><![CDATA[
failure messages as they arrive.
To use the command line reporter simply substitute it
for the HTML version...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
- $test = &new GroupTest('File test');
- $test->addTestFile('tests/file_test.php');
- $test->run(]]><![CDATA[new TextReporter()]]><![CDATA[);
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('File test');
+ $test-&gt;addTestFile('tests/file_test.php');
+ $test-&gt;run(new TextReporter());
+?&gt;
+</programlisting>
Then invoke the test suite from the command line...
<pre class="shell">
php file_test.php
@@ -332,33 +334,33 @@ Test cases run: 1/1, Failures: 1, Exceptions: 0
method.
We can use that result to exit the script with the desired return
code...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
- $test = &new GroupTest('File test');
- $test->addTestFile('tests/file_test.php');
- ]]><![CDATA[exit ($test->run(new TextReporter()) ? 0 : 1);]]><![CDATA[
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('File test');
+ $test-&gt;addTestFile('tests/file_test.php');
+ exit ($test-&gt;run(new TextReporter()) ? 0 : 1);
+?&gt;
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
- $test = &new GroupTest('File test');
- $test->addTestFile('tests/file_test.php');
- ]]><![CDATA[if (TextReporter::inCli()) {]]><![CDATA[
- exit ($test->run(new TextReporter()) ? 0 : 1);
- ]]><![CDATA[}]]><![CDATA[
- $test->run(new HtmlReporter());
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('File test');
+ $test-&gt;addTestFile('tests/file_test.php');
+ if (TextReporter::inCli()) {
+ exit ($test-&gt;run(new TextReporter()) ? 0 : 1);
+ }
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
This is the form used within SimpleTest itself.
</para>
</refsect1>
@@ -394,15 +396,15 @@ Test cases run: 1/1, Failures: 1, Exceptions: 0
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...
-<program-listing role="php"><![CDATA[
-<?php
+<programlisting role="php">
+&lt;?php
require_once('simpletest/xml.php');
...
- $parser = &new SimpleTestXmlParser(new HtmlReporter());
- $parser->parse($test_output);
-?>
-]]></program-listing>
+ $parser = &amp;new SimpleTestXmlParser(new HtmlReporter());
+ $parser-&gt;parse($test_output);
+?&gt;
+</programlisting>
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.
@@ -424,19 +426,19 @@ Test cases run: 1/1, Failures: 1, Exceptions: 0
servers.
A test case already exists to do this within the SimpleTest
framework, but it is currently experimental...
-<program-listing role="php"><![CDATA[
-<?php
- ]]><![CDATA[require_once('../remote.php');]]><![CDATA[
+<programlisting role="php">
+&lt;?php
+ require_once('../remote.php');
require_once('../reporter.php');
$test_url = ...;
$dry_url = ...;
- $test = &new GroupTest('Remote tests');
- $test->addTestCase(]]><![CDATA[new RemoteTestCase($test_url, $dry_url)]]><![CDATA[);
- $test->run(new HtmlReporter());
-?>
-]]></program-listing>
+ $test = &amp;new GroupTest('Remote tests');
+ $test-&gt;addTestCase(new RemoteTestCase($test_url, $dry_url));
+ $test-&gt;run(new HtmlReporter());
+?&gt;
+</programlisting>
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.
View
177 tutorials/SimpleTest/ServerStubs.pkg
@@ -4,7 +4,7 @@
<refname>Server stubs</refname>
<refpurpose/>
</refnamediv>
- {@doc}
+ {@toc}
<refsect1 id="{@id what}">
<title>What are server stubs?</title>
@@ -24,8 +24,8 @@
<para>
All we need is an existing class, say a database connection
that looks like this...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[class DatabaseConnection {
+<programlisting role="php">
+class DatabaseConnection {
function DatabaseConnection() {
}
@@ -34,37 +34,37 @@
function selectQuery() {
}
-}]]><![CDATA[
-]]></program-listing>
+}
+</programlisting>
The class does not need to have been implemented yet.
To create a stub version of the class we need to include the
server stub library and run the generator...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[require_once('simpletest/mock_objects.php');
+<programlisting role="php">
+require_once('simpletest/mock_objects.php');
require_once('database_connection.php');
-Stub::generate('DatabaseConnection');]]><![CDATA[
-]]></program-listing>
+Stub::generate('DatabaseConnection');
+</programlisting>
This generates a clone class called
<span class="new_code">StubDatabaseConnection</span>.
We can now create instances of the new class within
our prototype script...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
require_once('simpletest/mock_objects.php');
require_once('database_connection.php');
Stub::generate('DatabaseConnection');
-]]><![CDATA[
+
$connection = new StubDatabaseConnection();
-]]><![CDATA[
-]]></program-listing>
+
+</programlisting>
The stub version of a class has all the methods of the original
so that operations like
<span class="new_code">$connection-&gt;query()</span> are still
legal.
The return value will be <span class="new_code">null</span>,
but we can change that with...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[$connection->setReturnValue('query', 37)]]><![CDATA[
-]]></program-listing>
+<programlisting role="php">
+$connection-&gt;setReturnValue('query', 37)
+</programlisting>
Now every time we call
<span class="new_code">$connection-&gt;query()</span> we get
the result of 37.
@@ -86,27 +86,27 @@ $connection = new StubDatabaseConnection();
being tested.
For these we need to set up sequences of values.
Let's say we have a simple iterator that looks like this...
-<program-listing role="php"><![CDATA[
+<programlisting role="php">
class Iterator {
function Iterator() {
}
function next() {
}
}
-]]></program-listing>
+</programlisting>
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...
-<program-listing role="php"><![CDATA[
-]]><![CDATA[Stub::generate('Iterator');
+<programlisting role="php">
+Stub::generate('Iterator');
$iterator = new StubIterator();
-$iterator->setReturnValue('next', false);
-$iterator->setReturnValueAt(0, 'next', 'First string');
-$iterator->setReturnValueAt(1, 'next', 'Second string');]]><![CDATA[
-]]></program-listing>
+$iterator-&gt;setReturnValue('next', false);
+$iterator-&gt;setReturnValueAt(0, 'next', 'First string');
+$iterator-&gt;setReturnValueAt(1, 'next', 'Second string');
+</programlisting>
When <span class="new_code">next()</span> is called on the
stub iterator it will first return "First string",
on the second call "Second string" will be returned
@@ -121,15 +121,15 @@ $iterator->setReturnValueAt(1, 'next', 'Second string');]]><![CDATA[
<span class="new_code">get()</span> operation.
An example of this is an information holder with name/value pairs.