diff options
Diffstat (limited to 'tests/UnitTests/simpletest/docs/en/server_stubs_documentation.html')
-rw-r--r-- | tests/UnitTests/simpletest/docs/en/server_stubs_documentation.html | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/tests/UnitTests/simpletest/docs/en/server_stubs_documentation.html b/tests/UnitTests/simpletest/docs/en/server_stubs_documentation.html new file mode 100644 index 00000000..445ba63e --- /dev/null +++ b/tests/UnitTests/simpletest/docs/en/server_stubs_documentation.html @@ -0,0 +1,388 @@ +<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>SimpleTest for PHP server stubs documentation</title>
+<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
+</head>
+<body>
+<div class="menu_back">
+<div class="menu">
+<h2>
+<a href="index.html">SimpleTest</a>
+</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>
+<span class="chosen">Server stubs</span>
+</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>Server stubs documentation</h1>
+<div class="content">
+ <p>
+<a class="target" name="what">
+<h2>What are server stubs?</h2>
+</a>
+</p>
+ <p>
+ This was originally a pattern named by Robert Binder (Testing
+ object-oriented systems: models, patterns, and tools,
+ Addison-Wesley) in 1999.
+ A server stub is a simulation of an object or component.
+ It should exactly replace a component in a system for test
+ or prototyping purposes, but remain lightweight.
+ This allows tests to run more quickly, or if the simulated
+ class has not been written, to run at all.
+ </p>
+
+ <p>
+<a class="target" name="creation">
+<h2>Creating server stubs</h2>
+</a>
+</p>
+ <p>
+ All we need is an existing class, say a database connection
+ that looks like this...
+<pre>
+<strong>class DatabaseConnection {
+ function DatabaseConnection() {
+ }
+
+ function query() {
+ }
+
+ function selectQuery() {
+ }
+}</strong>
+</pre>
+ The class does not need to have been implemented yet.
+ To create a stub version of the class we need to include the
+ server stub library and run the generator...
+<pre>
+<strong>require_once('simpletest/mock_objects.php');
+require_once('database_connection.php');
+Stub::generate('DatabaseConnection');</strong>
+</pre>
+ 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...
+<pre>
+require_once('simpletest/mock_objects.php');
+require_once('database_connection.php');
+Stub::generate('DatabaseConnection');
+<strong>
+$connection = new StubDatabaseConnection();
+</strong>
+</pre>
+ The stub version of a class has all the methods of the original
+ so that operations like
+ <span class="new_code">$connection->query()</span> are still
+ legal.
+ The return value will be <span class="new_code">null</span>,
+ but we can change that with...
+<pre>
+<strong>$connection->setReturnValue('query', 37)</strong>
+</pre>
+ Now every time we call
+ <span class="new_code">$connection->query()</span> we get
+ the result of 37.
+ We can set the return value to anything, say a hash of
+ imaginary database results or a list of persistent objects.
+ Parameters are irrelevant here, we always get the same
+ values back each time once they have been set up this way.
+ That may not sound like a convincing replica of a
+ database connection, but for the half a dozen lines of
+ a test method it is usually all you need.
+ </p>
+
+ <p>
+<a class="target" name="patterns">
+<h2>Simulation patterns</h2>
+</a>
+</p>
+ <p>
+ Things aren't always that simple though.
+ One common problem is iterators, where constantly returning
+ the same value could cause an endless loop in the object
+ being tested.
+ For these we need to set up sequences of values.
+ Let's say we have a simple iterator that looks like this...
+<pre>
+class Iterator {
+ function Iterator() {
+ }
+
+ function next() {
+ }
+}
+</pre>
+ This is about the simplest iterator you could have.
+ Assuming that this iterator only returns text until it
+ reaches the end, when it returns false, we can simulate it
+ with...
+<pre>
+<strong>Stub::generate('Iterator');
+
+$iterator = new StubIterator();
+$iterator->setReturnValue('next', false);
+$iterator->setReturnValueAt(0, 'next', 'First string');
+$iterator->setReturnValueAt(1, 'next', 'Second string');</strong>
+</pre>
+ When <span class="new_code">next()</span> is called on the
+ stub iterator it will first return "First string",
+ on the second call "Second string" will be returned
+ and on any other call <span class="new_code">false</span> will
+ be returned.
+ The sequenced return values take precedence over the constant
+ return value.
+ The constant one is a kind of default if you like.
+ </p>
+ <p>
+ Another tricky situation is an overloaded
+ <span class="new_code">get()</span> operation.
+ An example of this is an information holder with name/value pairs.
+ Say we have a configuration class like...
+<pre>
+class Configuration {
+ function Configuration() {
+ }
+
+ function getValue($key) {
+ }
+}
+</pre>
+ This is a classic situation for using stub objects as
+ actual configuration will vary from machine to machine,
+ hardly helping the reliability of our tests if we use it
+ directly.
+ The problem though is that all the data comes through the
+ <span class="new_code">getValue()</span> method and yet
+ we want different results for different keys.
+ Luckily the stubs have a filter system...
+<pre>
+<strong>Stub::generate('Configuration');
+
+$config = &new StubConfiguration();
+$config->setReturnValue('getValue', 'primary', array('db_host'));
+$config->setReturnValue('getValue', 'admin', array('db_user'));
+$config->setReturnValue('getValue', 'secret', array('db_password'));</strong>
+</pre>
+ The extra parameter is a list of arguments to attempt
+ to match.
+ In this case we are trying to match only one argument which
+ is the look up key.
+ Now when the server stub has the
+ <span class="new_code">getValue()</span> method invoked
+ like this...
+<pre>
+$config->getValue('db_user');
+</pre>
+ ...it will return "admin".
+ It finds this by attempting to match the calling arguments
+ to its list of returns one after another until
+ a complete match is found.
+ </p>
+ <p>
+ You can set a default argument argument like so...
+<pre>
+<strong>
+$config->setReturnValue('getValue', false, array('*'));</strong>
+</pre>
+ This is not the same as setting the return value without
+ any argument requirements like this...
+<pre>
+<strong>
+$config->setReturnValue('getValue', false);</strong>
+</pre>
+ In the first case it will accept any single argument,
+ but exactly one is required.
+ In the second case any number of arguments will do and
+ it acts as a catchall after all other matches.
+ Note that if we add further single parameter options after
+ the wildcard in the first case, they will be ignored as the wildcard
+ will match first.
+ With complex parameter lists the ordering could be important
+ or else desired matches could be masked by earlier wildcard
+ ones.
+ Declare the most specific matches first if you are not sure.
+ </p>
+ <p>
+ There are times when you want a specific object to be
+ dished out by the stub rather than just a copy.
+ The PHP copy semantics force us to use a different method
+ for this.
+ You might be simulating a container for example...
+<pre>
+class Thing {
+}
+
+class Vector {
+ function Vector() {
+ }
+
+ function get($index) {
+ }
+}
+</pre>
+ In this case you can set a reference into the stub's
+ return list...
+<pre>
+Stub::generate('Vector');
+
+$thing = new Thing();<strong>
+$vector = &new StubVector();
+$vector->setReturnReference('get', $thing, array(12));</strong>
+</pre>
+ With this arrangement you know that every time
+ <span class="new_code">$vector->get(12)</span> is
+ called it will return the same
+ <span class="new_code">$thing</span> each time.
+ </p>
+ <p>
+ These three factors, timing, parameters and whether to copy,
+ can be combined orthogonally.
+ For example...
+<pre>
+$complex = &new StubComplexThing();
+$stuff = new Stuff();<strong>
+$complex->setReturnReferenceAt(3, 'get', $stuff, array('*', 1));</strong>
+</pre>
+ This will return the <span class="new_code">$stuff</span> only on the third
+ call and only if two parameters were set the second of
+ which must be the integer 1.
+ That should cover most simple prototyping situations.
+ </p>
+ <p>
+ A final tricky case is one object creating another, known
+ as a factory pattern.
+ Suppose that on a successful query to our imaginary
+ database, a result set is returned as an iterator with
+ each call to <span class="new_code">next()</span> giving
+ one row until false.
+ This sounds like a simulation nightmare, but in fact it can all
+ be stubbed using the mechanics above.
+ </p>
+ <p>
+ Here's how...
+<pre>
+Stub::generate('DatabaseConnection');
+Stub::generate('ResultIterator');
+
+class DatabaseTest extends UnitTestCase {
+
+ function testUserFinder() {<strong>
+ $result = &new StubResultIterator();
+ $result->setReturnValue('next', false);
+ $result->setReturnValueAt(0, 'next', array(1, 'tom'));
+ $result->setReturnValueAt(1, 'next', array(3, 'dick'));
+ $result->setReturnValueAt(2, 'next', array(6, 'harry'));
+
+ $connection = &new StubDatabaseConnection();
+ $connection->setReturnValue('query', false);
+ $connection->setReturnReference(
+ 'query',
+ $result,
+ array('select id, name from users'));</strong>
+
+ $finder = &new UserFinder($connection);
+ $this->assertIdentical(
+ $finder->findNames(),
+ array('tom', 'dick', 'harry'));
+ }
+}
+</pre>
+ Now only if our
+ <span class="new_code">$connection</span> is called with the correct
+ <span class="new_code">query()</span> will the
+ <span class="new_code">$result</span> be returned that is
+ itself exhausted after the third call to <span class="new_code">next()</span>.
+ This should be enough
+ information for our <span class="new_code">UserFinder</span> class,
+ the class actually
+ being tested here, to come up with goods.
+ A very precise test and not a real database in sight.
+ </p>
+
+ <p>
+<a class="target" name="options">
+<h2>Stub creation options</h2>
+</a>
+</p>
+ <p>
+ There are some additional options when creating stubs.
+ At the generation stage we can change the class name...
+<pre>
+<strong>Stub::generate('Iterator', 'MyStubIterator');
+$iterator = &new MyStubIterator();
+</strong>
+</pre>
+ This is not very useful in itself as there would be no difference
+ in this class and the default except for the name.
+ However we can also add additional methods not found in the
+ original interface...
+<pre>
+class Iterator {
+}
+<strong>Stub::generate('Iterator', 'PrototypeIterator', array('next', 'isError'));
+$iterator = &new PrototypeIterator();
+$iterator->setReturnValue('next', 0);
+</strong>
+</pre>
+ The <span class="new_code">next()</span> and
+ <span class="new_code">isError()</span> methods can now have
+ return values set just as if they existed in the original class.
+ </p>
+ <p>
+ One other esoteric way of customising the stubs is to change
+ the default wildcard used for parameter matching.
+<pre>
+<strong>Stub::generate('Connection');
+$iterator = &new StubConnection('wild');
+$iterator->setReturnValue('query', array('id' => 33), array('wild'));
+</strong>
+</pre>
+ The only reason to do this is if you genuinely wanted to test
+ against the literal string "*" and didn't want it
+ interpreted as "any".
+ </p>
+
+ </div>
+<div class="copyright">
+ Copyright<br>Marcus Baker, Jason Sweat, Perrick Penet 2004
+ </div>
+</body>
+</html>
|