From b2e97539e7af7712b04dd5c2610a454d09aa0333 Mon Sep 17 00:00:00 2001 From: wei <> Date: Fri, 7 Jul 2006 23:18:19 +0000 Subject: Update simpletest --- .../docs/en/authentication_documentation.html | 48 ++-- .../simpletest/docs/en/browser_documentation.html | 27 +- .../docs/en/expectation_documentation.html | 40 ++- .../docs/en/form_testing_documentation.html | 13 +- .../docs/en/group_test_documentation.html | 5 +- tests/test_tools/simpletest/docs/en/index.html | 48 ++-- .../docs/en/mock_objects_documentation.html | 272 +++++++++++---------- tests/test_tools/simpletest/docs/en/overview.html | 154 ++++++------ .../docs/en/partial_mocks_documentation.html | 3 - .../simpletest/docs/en/reporter_documentation.html | 3 - .../docs/en/unit_test_documentation.html | 19 +- .../docs/en/web_tester_documentation.html | 31 +-- 12 files changed, 331 insertions(+), 332 deletions(-) (limited to 'tests/test_tools/simpletest/docs/en') diff --git a/tests/test_tools/simpletest/docs/en/authentication_documentation.html b/tests/test_tools/simpletest/docs/en/authentication_documentation.html index 0623023c..c90d61e5 100755 --- a/tests/test_tools/simpletest/docs/en/authentication_documentation.html +++ b/tests/test_tools/simpletest/docs/en/authentication_documentation.html @@ -21,9 +21,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • @@ -109,6 +106,19 @@ class AuthenticationTest extends WebTestCase { on the amount of detail you want to see.

    + One theme that runs through SimpleTest is the ability to use + SimpleExpectation objects wherever a simple + match is not enough. + If you want only an approximate match to the realm for + example, you can do this... +

    +class AuthenticationTest extends WebTestCase {
    +    function test401Header() {
    +        $this->get('http://www.lastcraft.com/protected/');
    +        $this->assertRealm(new PatternExpectation('/simpletest/i'));
    +    }
    +}
    +
    Most of the time we are not interested in testing the authentication itself, but want to get past it to test the pages underneath. @@ -116,7 +126,7 @@ class AuthenticationTest extends WebTestCase { an authentication response...
     class AuthenticationTest extends WebTestCase {
    -    function testAuthentication() {
    +    function testCanAuthenticate() {
             $this->get('http://www.lastcraft.com/protected/');
             $this->authenticate('Me', 'Secret');
             $this->assertTitle(...);
    @@ -208,9 +218,15 @@ class LogInTest extends WebTestCase {
     
    All we are doing is confirming that the cookie is set. As the value is likely to be rather cryptic it's not - really worth testing this. -

    -

    + really worth testing this with... +

    +class LogInTest extends WebTestCase {
    +    function testSessionCookieIsCorrectPattern() {
    +        $this->get('http://www.my-site.com/login.php');
    +        $this->assertCookie('SID', new PatternExpectation('/[a-f0-9]{32}/i'));
    +    }
    +}
    +
    The rest of the test would be the same as any other form, but we might want to confirm that we still have the same cookie after log-in as before we entered. @@ -224,8 +240,8 @@ class LogInTest extends WebTestCase { $session = $this->getCookie('SID'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); - $this->clickSubmit('Log in'); - $this->assertWantedPattern('/Welcome Me/'); + $this->click('Log in'); + $this->assertText('Welcome Me'); $this->assertCookie('SID', $session); } } @@ -243,7 +259,7 @@ class LogInTest extends WebTestCase { $this->get('http://www.my-site.com/login.php'); $this->setCookie('SID', 'Some other session'); $this->get('http://www.my-site.com/restricted.php'); - $this->assertWantedPattern('/Access denied/'); + $this->assertText('Access denied'); } } @@ -266,12 +282,12 @@ class LogInTest extends WebTestCase { $this->get('http://www.my-site.com/login.php'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); - $this->clickSubmit('Log in'); - $this->assertWantedPattern('/Welcome Me/'); + $this->click('Log in'); + $this->assertText('Welcome Me'); $this->restart(); $this->get('http://www.my-site.com/restricted.php'); - $this->assertWantedPattern('/Access denied/'); + $this->assertText('Access denied'); } } @@ -297,13 +313,13 @@ class LogInTest extends WebTestCase { $this->get('http://www.my-site.com/login.php'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); - $this->clickSubmit('Log in'); - $this->assertWantedPattern('/Welcome Me/'); + $this->click('Log in'); + $this->assertText('Welcome Me'); $this->ageCookies(3600); $this->restart(); $this->get('http://www.my-site.com/restricted.php'); - $this->assertWantedPattern('/Access denied/'); + $this->assertText('Access denied'); } } diff --git a/tests/test_tools/simpletest/docs/en/browser_documentation.html b/tests/test_tools/simpletest/docs/en/browser_documentation.html index ef54aaea..f6046a9d 100755 --- a/tests/test_tools/simpletest/docs/en/browser_documentation.html +++ b/tests/test_tools/simpletest/docs/en/browser_documentation.html @@ -21,9 +21,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • @@ -76,9 +73,9 @@ $browser = &new SimpleBrowser(); $browser->get('http://php.net/'); - $browser->clickLink('reporting bugs'); - $browser->clickLink('statistics'); - $page = $browser->clickLink('PHP 5 bugs only'); + $browser->click('reporting bugs'); + $browser->click('statistics'); + $page = $browser->click('PHP 5 bugs only'); preg_match('/status=Open.*?by=Any.*?(\d+)<\/a>/', $page, $matches); print $matches[1]; ?> @@ -297,14 +294,22 @@ useFrames()Enables frames support + + +ignoreCookies()Disables sending and receiving of cookies + + +useCookies()Enables cookie support The methods SimpleBrowser::setConnectionTimeout() SimpleBrowser::setMaximumRedirects(), SimpleBrowser::setMaximumNestedFrames(), - SimpleBrowser::ignoreFrames() and - SimpleBrowser::useFrames() continue to apply + SimpleBrowser::ignoreFrames(), + SimpleBrowser::useFrames(), + SimpleBrowser::ignoreCookies() and + SimpleBrowser::useCokies() continue to apply to every subsequent request. The other methods are frames aware. This means that if you have an individual frame that is not @@ -332,7 +337,7 @@ class TestOfRegistration extends UnitTestCase { $browser->get('http://my-site.com/register.php'); $browser->setField('email', 'me@here'); $browser->setField('password', 'Secret'); - $browser->clickSubmit('Register'); + $browser->click('Register'); $authenticator = &new Authenticator(); $member = &$authenticator->findByEmail('me@here'); @@ -361,14 +366,14 @@ class TestOfSecurity extends UnitTestCase { $first->get('http://my-site.com/login.php'); $first->setField('name', 'Me'); $first->setField('password', 'Secret'); - $first->clickSubmit('Enter'); + $first->click('Enter'); $this->assertEqual($first->getTitle(), 'Welcome'); $second = &new SimpleBrowser(); $second->get('http://my-site.com/login.php'); $second->setField('name', 'Me'); $second->setField('password', 'Secret'); - $second->clickSubmit('Enter'); + $second->click('Enter'); $this->assertEqual($second->getTitle(), 'Access Denied'); } } diff --git a/tests/test_tools/simpletest/docs/en/expectation_documentation.html b/tests/test_tools/simpletest/docs/en/expectation_documentation.html index 0165988c..bd189b94 100755 --- a/tests/test_tools/simpletest/docs/en/expectation_documentation.html +++ b/tests/test_tools/simpletest/docs/en/expectation_documentation.html @@ -23,9 +23,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • @@ -101,8 +98,8 @@
     class TestOfNewsService extends UnitTestCase {
         ...
    -    function testConnectionFailure() {
    -        $writer = &new MockWriter($this);
    +    function testConnectionFailure() {<strong>
    +        $writer = &new MockWriter();
             $writer->expectOnce('write', array(
                     'Cannot connect to news service ' .
                     '"BBC News" at this time. ' .
    @@ -110,8 +107,6 @@ class TestOfNewsService extends UnitTestCase {
             
             $service = &new NewsService('BBC News');
             $service->publish($writer);
    -        
    -        $writer->tally();
         }
     }
     
    @@ -129,15 +124,13 @@ class TestOfNewsService extends UnitTestCase { class TestOfNewsService extends UnitTestCase { ... function testConnectionFailure() { - $writer = &new MockWriter($this); + $writer = &new MockWriter(); $writer->expectOnce( 'write', - array(new WantedPatternExpectation('/cannot connect/i'))); + array(new PatternExpectation('/cannot connect/i'))); $service = &new NewsService('BBC News'); $service->publish($writer); - - $writer->tally(); } } @@ -179,10 +172,10 @@ class TestOfNewsService extends UnitTestCase { NotIndenticalExpectationInverts the mock object logic -WantedPatternExpectationUses a Perl Regex to match a string +PatternExpectationUses a Perl Regex to match a string -NoUnwantedPatternExpectationPasses only if failing a Perl Regex +NoPatternExpectationPasses only if failing a Perl Regex IsAExpectationChecks the type or class name only @@ -208,29 +201,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 - mock objects - or the - server stubs. + from mock objects, but also for selecting behaviour for the + mock objects. Anywhere a list of arguments is given, a list of expectation objects can be inserted instead.

    - Suppose we want an authorisation server stub to simulate a successful login + Suppose we want an authorisation server mock to simulate a successful login only if it receives a valid session object. We can do this as follows...

    -Stub::generate('Authorisation');
    +Mock::generate('Authorisation');
     
    -$authorisation = new StubAuthorisation();
    +$authorisation = new MockAuthorisation();
     $authorisation->setReturnValue(
             'isAllowed',
             true,
             array(new IsAExpectation('Session', 'Must be a session')));
     $authorisation->setReturnValue('isAllowed', false);
     
    - We have set the default stub behaviour to return false when + We have set the default mock behaviour to return false when isAllowed is called. When we call the method with a single parameter that is a Session object, it will return true. @@ -299,14 +289,14 @@ $authorisation->setReturnValue('isAllowed', false);

    The most crude way of doing this is to use the - SimpleTest::assertExpectation() method to + SimpleTest::assert() method to test against it directly...

     class TestOfNetworking extends UnitTestCase {
         ...
         function testGetValidIp() {
             $server = &new Server();
    -        $this->assertExpectation(
    +        $this->assert(
                     new ValidIp(),
                     $server->getIp(),
                     'Server IP address->%s');
    @@ -327,7 +317,7 @@ $authorisation->setReturnValue('isAllowed', false);
     class TestOfNetworking extends UnitTestCase {
         ...
         function assertValidIp($ip, $message = '%s') {
    -        $this->assertExpectation(new ValidIp(), $ip, $message);
    +        $this->assert(new ValidIp(), $ip, $message);
         }
         
         function testGetValidIp() {
    diff --git a/tests/test_tools/simpletest/docs/en/form_testing_documentation.html b/tests/test_tools/simpletest/docs/en/form_testing_documentation.html
    index b1e15b3d..50b634c0 100755
    --- a/tests/test_tools/simpletest/docs/en/form_testing_documentation.html
    +++ b/tests/test_tools/simpletest/docs/en/form_testing_documentation.html
    @@ -21,9 +21,6 @@
     Group tests
     
  • -Server stubs -
  • -
  • Mock objects
  • @@ -96,7 +93,9 @@ class SimpleFormTests extends WebTestCase { 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 name "a" and that it is currently set to the value - "A default" + "A default". + As usual, we could use a pattern expectation instead if a fixed + string.

    We could submit the form straight away, but first we'll change @@ -108,7 +107,7 @@ class SimpleFormTests extends WebTestCase { $this->get('http://www.my-site.com/'); $this->assertField('a', 'A default'); $this->setField('a', 'New value'); - $this->clickSubmit('Go'); + $this->click('Go'); } } @@ -235,7 +234,7 @@ class SimpleFormTests extends WebTestCase { $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'); + $this->click('Enable Privileges'); } } @@ -261,7 +260,7 @@ class SimpleFormTests extends WebTestCase { $this->post( 'http://www.my-site.com/add_user.php', array('type' => 'superuser')); - $this->assertNoUnwantedPattern('/user created/i'); + $this->assertNoText('user created'); } } diff --git a/tests/test_tools/simpletest/docs/en/group_test_documentation.html b/tests/test_tools/simpletest/docs/en/group_test_documentation.html index adbc66ef..1e14d31e 100755 --- a/tests/test_tools/simpletest/docs/en/group_test_documentation.html +++ b/tests/test_tools/simpletest/docs/en/group_test_documentation.html @@ -21,9 +21,6 @@ Group tests

  • -Server stubs -
  • -
  • Mock objects
  • @@ -87,7 +84,7 @@ class MyFileTestCase extends UnitTestCase { ... } - SimpleTestOptions::ignore('MyFileTestCase'); + SimpleTest::ignore('MyFileTestCase'); class FileTester extends MyFileTestCase { ... diff --git a/tests/test_tools/simpletest/docs/en/index.html b/tests/test_tools/simpletest/docs/en/index.html index 04797272..c7183c49 100755 --- a/tests/test_tools/simpletest/docs/en/index.html +++ b/tests/test_tools/simpletest/docs/en/index.html @@ -24,9 +24,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • @@ -101,26 +98,22 @@ We start by creating a test script which we will call tests/log_test.php and populate it as follows...
    -<?php
    -require_once('simpletest/unit_tester.php');
    -require_once('simpletest/reporter.php');
    -require_once('../classes/log.php');
    -?>
    -
    - Here the simpletest folder is either local or in the path. - You would have to edit these locations depending on where you - placed the toolset. - Next we create a test case... -
    -<?php
    +<?php
     require_once('simpletest/unit_tester.php');
     require_once('simpletest/reporter.php');
     require_once('../classes/log.php');
    -
    +
     class TestOfLogging extends UnitTestCase {
     }
     ?>
     
    + Here the simpletest folder is either local or in the path. + You would have to edit these locations depending on where you + placed the toolset. + The TestOfLogging is our frst test case and it's + currently empty. +

    +

    Now we have five lines of scaffolding code and still no tests. However from this part on we get return on our investment very quickly. We'll assume that the Log class @@ -376,21 +369,15 @@ Mock::generate('Log'); class TestOfSessionLogging extends UnitTestCase { function testLogInIsLogged() { - $log = &new MockLog($this); + $log = &new MockLog(); $log->expectOnce('message', array('User fred logged in.')); $session_pool = &new SessionPool($log); - $session_pool->logIn('fred'); - $log->tally(); + $session_pool->logIn('fred'); } } ?> - The tally() call is needed to - tell the mock object that time is up for the expected call - count. - Without it the mock would wait forever for the method - call to come in without ever actually notifying the test case. - The other test will be triggered when the call to + The test will be triggered when the call to message() is invoked on the MockLog object. The mock call will trigger a parameter comparison and then send the @@ -398,6 +385,13 @@ class TestOfSessionLogging extends UnitTestCase { Wildcards can be included here too so as to prevent tests becoming too specific.

    +

    + If the mock reaches the end of the test case without the + method being called, the expectOnce() + expectation will trigger a test failure. + In other words the mocks can detect the absence of + behaviour as well as the presence. +

    The mock objects in the SimpleTest suite can have arbitrary return values set, sequences of returns, return values @@ -439,12 +433,12 @@ class TestOfAbout extends WebTestCase { function setUp() { $this->get('http://test-server/index.php'); - $this->clickLink('About'); + $this->click('About'); } function testSearchEngineOptimisations() { $this->assertTitle('A long title about us for search engines'); - $this->assertWantedPattern('/a popular keyphrase/i'); + $this->assertPattern('/a popular keyphrase/i'); } } $test = &new TestOfAbout(); diff --git a/tests/test_tools/simpletest/docs/en/mock_objects_documentation.html b/tests/test_tools/simpletest/docs/en/mock_objects_documentation.html index 2f8a1f90..eb32c619 100755 --- a/tests/test_tools/simpletest/docs/en/mock_objects_documentation.html +++ b/tests/test_tools/simpletest/docs/en/mock_objects_documentation.html @@ -21,9 +21,6 @@ Group tests

  • -Server stubs -
  • -
  • Mock objects
  • @@ -76,7 +73,17 @@

    If mock objects only behaved as actors they would simply be - known as server stubs. + known as server stubs. + 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.

    However, the mock objects not only play a part (by supplying chosen @@ -87,6 +94,8 @@ If expectations are not met they save us the effort of writing a failed test assertion by performing that duty on our behalf. +

    +

    In the case of an imaginary database connection they can test that the query, say SQL, was correctly formed by the object that is using the connection. @@ -138,7 +147,7 @@ Mock::generate('DatabaseConnection'); class MyTestCase extends UnitTestCase { function testSomething() { - $connection = &new MockDatabaseConnection($this); + $connection = &new MockDatabaseConnection(); } } @@ -155,19 +164,27 @@ class MyTestCase extends UnitTestCase {

    - The mock version of a class has all the methods of the original + The mock version of a class has all the methods of the original, so that operations like $connection->query() are still legal. - As with stubs we can replace the default null return values... + The return value will be null, + but we can change that with...

    -$connection->setReturnValue('query', 37);
    +$connection->setReturnValue('query', 37)
     
    Now every time we call $connection->query() we get the result of 37. - As with the stubs we can set wildcards and we can overload the - wildcard parameter. + 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. +

    +

    We can also add extra methods to the mock when generating it and choose our own class name...

    @@ -180,8 +197,12 @@ class MyTestCase extends UnitTestCase {
                     You can create a special mock to simulate this situation.
                 

    - All of the patterns available with server stubs are available - to mock objects... + 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...

     class Iterator {
         function Iterator() {
    @@ -191,7 +212,8 @@ class Iterator {
         }
     }
     
    - Again, assuming that this iterator only returns text until it + 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...
    @@ -200,7 +222,7 @@ Mock::generate('Iterator');
     class IteratorTest extends UnitTestCase() {
         
         function testASequence() {
    -        $iterator = &new MockIterator($this);
    +        $iterator = &new MockIterator();
             $iterator->setReturnValue('next', false);
             $iterator->setReturnValueAt(0, 'next', 'First string');
             $iterator->setReturnValueAt(1, 'next', 'Second string');
    @@ -218,7 +240,10 @@ class IteratorTest extends UnitTestCase() {
                     The constant one is a kind of default if you like.
                 

    - A repeat of the stubbed information holder with name/value pairs... + Another tricky situation is an overloaded + get() operation. + An example of this is an information holder with name/value pairs. + Say we have a configuration class like...

     class Configuration {
         function Configuration() {
    @@ -237,7 +262,7 @@ class Configuration {
                     we want different results for different keys.
                     Luckily the mocks have a filter system...
     
    -$config = &new MockConfiguration($this);
    +$config = &new MockConfiguration();
     $config->setReturnValue('getValue', 'primary', array('db_host'));
     $config->setReturnValue('getValue', 'admin', array('db_user'));
     $config->setReturnValue('getValue', 'secret', array('db_password'));
    @@ -257,10 +282,36 @@ $config->getValue('db_user')
                     to its list of returns one after another until
                     a complete match is found.
                 

    +

    + You can set a default argument argument like so... +

    +
    +$config->setReturnValue('getValue', false, array('*'));
    +
    + This is not the same as setting the return value without + any argument requirements like this... +
    +
    +$config->setReturnValue('getValue', false);
    +
    + 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. +

    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... + The PHP4 copy semantics force us to use a different method + for this. + You might be simulating a container for example...

     class Thing {
     }
    @@ -276,14 +327,79 @@ class Vector {
                     In this case you can set a reference into the mock's
                     return list...
     
    -$thing = new Thing();
    -$vector = &new MockVector($this);
    +$thing = &new Thing();
    +$vector = &new MockVector();
     $vector->setReturnReference('get', $thing, array(12));
     
    With this arrangement you know that every time $vector->get(12) is called it will return the same $thing each time. + This is compatible with PHP5 as well. +

    +

    + These three factors, timing, parameters and whether to copy, + can be combined orthogonally. + For example... +

    +$complex = &new MockComplexThing();
    +$stuff = &new Stuff();
    +$complex->setReturnReferenceAt(3, 'get', $stuff, array('*', 1));
    +
    + This will return the $stuff 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. +

    +

    + 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 next() giving + one row until false. + This sounds like a simulation nightmare, but in fact it can all + be mocked using the mechanics above. +

    +

    + Here's how... +

    +Mock::generate('DatabaseConnection');
    +Mock::generate('ResultIterator');
    +
    +class DatabaseTest extends UnitTestCase {
    +    
    +    function testUserFinder() {
    +        $result = &new MockResultIterator();
    +        $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 MockDatabaseConnection();
    +        $connection->setReturnValue('query', false);
    +        $connection->setReturnReference(
    +                'query',
    +                $result,
    +                array('select id, name from users'));
    +                
    +        $finder = &new UserFinder($connection);
    +        $this->assertIdentical(
    +                $finder->findNames(),
    +                array('tom', 'dick', 'harry'));
    +    }
    +}
    +
    + Now only if our + $connection is called with the correct + query() will the + $result be returned that is + itself exhausted after the third call to next(). + This should be enough + information for our UserFinder class, + the class actually + being tested here, to come up with goods. + A very precise test and not a real database in sight.

    @@ -388,18 +504,16 @@ Mock::generate('Log'); class LoggingSessionPoolTest extends UnitTestCase { ... function testFindSessionLogging() { - $session = &new MockSession($this); - $pool = &new MockSessionPool($this); + $session = &new MockSession(); + $pool = &new MockSessionPool(); $pool->setReturnReference('findSession', $session); $pool->expectOnce('findSession', array('abc')); - $log = &new MockLog($this); + $log = &new MockLog(); $log->expectOnce('message', array('Starting session abc')); $logging_pool = &new LoggingSessionPool($pool, $log); - $this->assertReference($logging_pool->findSession('abc'), $session); - $pool->tally(); - $log->tally(); + $this->assertReference($logging_pool->findSession('abc'), $session); } }

    @@ -426,15 +540,6 @@ class LoggingSessionPoolTest extends UnitTestCase { You can have wildcards and sequences and the order of evaluation is the same.

    -

    - If the call is never made then neither a pass nor a failure will - generated. - To get around this we must tell the mock when the test is over - so that the object can decide if the expectation has been met. - The unit tester assertion for this is triggered by the - tally() call at the end of - the test. -

    We use the same pattern to set up the mock logger. We tell it that it should have @@ -448,11 +553,6 @@ class LoggingSessionPoolTest extends UnitTestCase { LoggingSessionPool and feed it our preset mock objects. Everything is now under our control. - Finally we confirm that the - $session we gave our decorator - is the one that we get back and tell the mocks to run their - internal call count tests with the - tally() calls.

    This is still quite a bit of test code, but the code is very @@ -477,11 +577,11 @@ class LoggingSessionPoolTest extends UnitTestCase { - expectArguments($method, $args) + expect($method, $args) No - expectArgumentsAt($timing, $method, $args) + expectAt($timing, $method, $args) No @@ -589,8 +689,8 @@ class LoggingSessionPoolTest extends UnitTestCase { Mock::generate('Connection', 'BasicMockConnection'); class MockConnection extends BasicMockConnection { - function MockConnection(&$test, $wildcard = '*') { - $this->BasicMockConnection($test, $wildcard); + function MockConnection() { + $this->BasicMockConnection(); $this->setReturn('query', false); } } @@ -619,92 +719,6 @@ class LoggingSessionPoolTest extends UnitTestCase { stages of testing.

    -

    - -

    I think SimpleTest stinks!

    - -

    -

    - But at the time of writing it is the only one with mock objects, - so are you stuck with it? -

    -

    - No, not at all. - 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... -

    -class PHPUnit {
    -    function PHPUnit() {
    -    }
    -    
    -    function assertion($message, $assertion) {
    -    }
    -    ...
    -}
    -
    - All the assertion() 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... -
    -$unit_test = new PHPUnit();
    -$unit_test>assertion('I hope this file exists', file_exists('my_file'));
    -
    - How do you use mocks with this? -

    -

    - There is a protected method on the base mock class - SimpleMock called - _assertTrue() and - by overriding this method we can use our own assertion format. - We start with a subclass, in say my_mock.php... -

    -<?php
    -    require_once('simpletest/mock_objects.php');
    -    
    -    class MyMock extends SimpleMock() {
    -        function MyMock(&$test, $wildcard) {
    -            $this->SimpleMock($test, $wildcard);
    -        }
    -        
    -        function _assertTrue($assertion, $message) {
    -            $test = &$this->getTest();
    -            $test->assertion($message, $assertion);
    -        }
    -    }
    -?>
    -
    - Now instantiating MyMock 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... -
    -<?php
    -    require_once('simpletst/mock_objects.php');
    -    
    -    class MyMock extends SimpleMock() {
    -        function MyMock($test, $wildcard) {
    -            $this->SimpleMock(&$test, $wildcard);
    -        }
    -        
    -        function _assertTrue($assertion, $message , &$test) {
    -            $test->assertion($message, $assertion);
    -        }
    -    }
    -    SimpleTestOptions::setMockBaseClass('MyMock');
    -?>
    -
    - From now on you just include my_mock.php instead of the - default mock_objects.php version and you can introduce - mock objects into your existing test suite. -

    -
  • -Server stubs -
  • -
  • Mock objects
  • @@ -151,8 +148,7 @@ class MySiteTest extends WebTestCase { milestones rather depends on time available. Green stuff has been coded, but not necessarily released yet. If you have a pressing need for a green but unreleased feature - then you should check-out the code from sourceforge CVS directly. - A released feature is marked as "Done". + then you should check-out the code from Sourceforge CVS directly. @@ -163,12 +159,12 @@ class MySiteTest extends WebTestCase { - + - + @@ -176,41 +172,20 @@ class MySiteTest extends WebTestCase { Reading a file with test cases and loading them into a group test automatically - + - + - - - - - - - - - - - + - - - - - - + @@ -218,32 +193,32 @@ class MySiteTest extends WebTestCase { Mocking parts of a class for testing less than a class or for complex simulations - + - + - + - + - + - + @@ -251,25 +226,15 @@ class MySiteTest extends WebTestCase { Allows multi host testing and the integration of acceptance testing extensions - + - - - - - - - - - - - + - + @@ -277,31 +242,39 @@ class MySiteTest extends WebTestCase { Fetching protected web pages with basic authentication only - - - - - - + - + - + - + + + + + + + + + + + - - + + @@ -310,28 +283,43 @@ class MySiteTest extends WebTestCase { - - + + - - + + + + + + + - - + + + + + + + - - + + + + + + +
    Unit test case Core test case class and assertionsDone1.0
    Html display Simplest possible displayDone1.0
    Autoloading of test casesDone1.0
    Mock objects code generatorMock objects Objects capable of simulating other objects removing test dependencies Done
    Server stubs - Mocks without expectations to be used outside of test cases, - e.g. for prototyping - Done
    Integration of other unit testers - The ability to read and simulate test cases from PHPUnit - and PEAR::PhpUnit - Done1.0
    Web test caseBasic pattern matching of fetched pagesDone
    HTML parsing of pages Allows link following and title tag matchingDone1.0
    Partial mocksDone1.0
    Web cookie handling Correct handling of cookies when fetching pagesDone1.0
    Following redirects Page fetching automatically follows 300 redirectsDone1.0
    Form parsing Ability to submit simple forms and read default form valuesDone1.0
    Command line interface Test display without the need of a web browserDone1.0
    Exposure of expectation classes Can create precise tests with mocks as well as test casesDone1.0
    XML output and parsingDone1.0
    Command line test caseAllows testing of utilities and file handlingDone
    PHP Documentor compatibilityFully generated class level documentationDone
    Browser interfaceBrowser component Exposure of lower level web browser interface for more detailed test cases Done1.0
    HTTP authenticationDone
    Browser navigation buttonsBack, forward and retryDone1.0
    SSL support Can connect to https: pagesDone1.0
    Proxy support Can connect via. common proxiesDone1.0
    Frames support Handling of frames in web test casesDone1.0
    File upload testingCan simulate the input type file tag1.0.1
    Mocking interfaces + Can generate mock objects to interfaces as well as classes + and class interfaces are carried for type hints + 1.0.1
    Improved displayBetter web GUI with tree display of test casesReporting machinery enhancementsImproved message passing for better cooperation with IDEs 1.1
    1.1
    File upload testingCan simulate the input type file tagTesting exceptionsSimilar to testing PHP errors 1.1
    Mocking interfacesCan generate mock objects to interfaces as well as classesIFrame supportReads IFrame content that can be refreshed1.1
    Improved mock interfaceMore compact way of expressing mocks 2.0
    Testing exceptionsSimilar to testing PHP errorsHTML table assertionsCan match table elements to numerical assertions2.0
    XPath searching of HTML elementsMore flexible content matching 2.0
    XPath searching of elementsCan make use of HTML tidy for faster and more flexible content matchingAlternate HTML parsersCan detect compiled parsers for performance improvements 2.0
    Javascript suportUse of PECL module to add Javascript3.0
    - PHP5 migraton will start straight after the version 1.1 series, + PHP5 migraton will start straight after the version 1.0.1 series, whereupon PHP4 will no longer be supported. SimpleTest is currently compatible with PHP5, but will not make use of all of the new features until version 2. @@ -374,18 +362,6 @@ class MySiteTest extends WebTestCase { version at least has been upgraded for PHP5 and is recommended if you are porting existing JUnit test cases.

    -

    - Library writers don't seem to ship tests with their code very often - which is a shame. - Library code that includes tests can be more safely refactored and - the test code can act as additional documentation in a fairly standard - form. - This can save trawling the source code for clues when problems occour, - especially when upgrading such a library. - Libraries using SimpleTest for their unit testing include - WACT and - PEAR::XML_HTMLSax. -

    There is currently a sad lack of material on mock objects, which is a shame as unit testing without them is a lot more work. @@ -394,14 +370,15 @@ class MySiteTest extends WebTestCase { As a new technology there are plenty of discussions and debate on how to use mocks, often on Wikis such as Extreme Tuesday - or www.mockobjects.com + or www.mockobjects.com or the original C2 Wiki. Injecting mocks into a class is the main area of debate for which this paper on IBM makes a good starting point.

    - There are plenty of web testing tools, but most are written in Java and + There are plenty of web testing tools, but the scriptable ones + are mostly are written in Java and tutorials and advice are rather thin on the ground. The only hope is to look at the documentation for HTTPUnit, @@ -409,6 +386,13 @@ class MySiteTest extends WebTestCase { or JWebUnit and hope for clues. There are some XML driven test frameworks, but again most require Java to run. +

    +

    + A new generation of tools that run directly in the web browser + are now available. + These include + Selenium and + Watir. As SimpleTest does not support JavaScript you would probably have to look at these tools anyway if you have highly dynamic pages. diff --git a/tests/test_tools/simpletest/docs/en/partial_mocks_documentation.html b/tests/test_tools/simpletest/docs/en/partial_mocks_documentation.html index 20749415..6d7b6243 100755 --- a/tests/test_tools/simpletest/docs/en/partial_mocks_documentation.html +++ b/tests/test_tools/simpletest/docs/en/partial_mocks_documentation.html @@ -21,9 +21,6 @@ Group tests

  • -Server stubs -
  • -
  • Mock objects
  • diff --git a/tests/test_tools/simpletest/docs/en/reporter_documentation.html b/tests/test_tools/simpletest/docs/en/reporter_documentation.html index 44be8b1e..ead61175 100755 --- a/tests/test_tools/simpletest/docs/en/reporter_documentation.html +++ b/tests/test_tools/simpletest/docs/en/reporter_documentation.html @@ -21,9 +21,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • diff --git a/tests/test_tools/simpletest/docs/en/unit_test_documentation.html b/tests/test_tools/simpletest/docs/en/unit_test_documentation.html index 6aa8d8a7..47b61eca 100755 --- a/tests/test_tools/simpletest/docs/en/unit_test_documentation.html +++ b/tests/test_tools/simpletest/docs/en/unit_test_documentation.html @@ -21,9 +21,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • @@ -162,6 +159,12 @@ class FileTestCase extends UnitTestCase { assertNotEqual($x, $y)Fail if $x == $y is true + + +assertWithinMargin($x, $y, $m)Fail if abs($x - $y) < $m is false + + +assertOutsideMargin($x, $y, $m)Fail if abs($x - $y) < $m is true assertIdentical($x, $y)Fail if $x == $y is false or a type mismatch @@ -176,19 +179,19 @@ class FileTestCase extends UnitTestCase { assertCopy($x, $y)Fail if $x and $y are the same variable -assertWantedPattern($p, $x)Fail unless the regex $p matches $x +assertPattern($p, $x)Fail unless the regex $p matches $x -assertNoUnwantedPattern($p, $x)Fail if the regex $p matches $x +assertNoPattern($p, $x)Fail if the regex $p matches $x assertNoErrors()Fail if any PHP error occoured -assertError($x)Fail if no PHP error or incorrect message +assertError($x)Fail if no PHP error or incorrect message/expectation -assertErrorPattern($p)Fail unless the error matches the regex $p +assertExpectation($e)Fail on failed expectation object @@ -226,7 +229,7 @@ $this->assertReference($a, $b); Will fail as the variable $a is a copy of $b.
    -$this->assertWantedPattern('/hello/i', 'Hello world');
    +$this->assertPattern('/hello/i', 'Hello world');
     
    This will pass as using a case insensitive match the string hello is contained in Hello world. diff --git a/tests/test_tools/simpletest/docs/en/web_tester_documentation.html b/tests/test_tools/simpletest/docs/en/web_tester_documentation.html index 51f604be..99dacacc 100755 --- a/tests/test_tools/simpletest/docs/en/web_tester_documentation.html +++ b/tests/test_tools/simpletest/docs/en/web_tester_documentation.html @@ -21,9 +21,6 @@ Group tests
  • -Server stubs -
  • -
  • Mock objects
  • @@ -153,7 +150,7 @@ class TestOfLastcraft extends WebTestCase { function testHomepage() { $this->get('http://www.lastcraft.com/'); - $this->assertWantedPattern('/why the last craft/i'); + $this->assertTest('Why the last craft'); } } @@ -169,16 +166,16 @@ class TestOfLastcraft extends WebTestCase { assertTitle($title)Pass if title is an exact match -assertWantedPattern($pattern)A Perl pattern match against the page content +assertPattern($pattern)A Perl pattern match against the page content -assertNoUnwantedPattern($pattern)A Perl pattern match to not find content +assertNoPattern($pattern)A Perl pattern match to not find content -assertWantedText($text)Pass if matches visible and "alt" text +assertText($text)Pass if matches visible and "alt" text -assertNoUnwantedText($text)Pass if doesn't match visible and "alt" text +assertNoText($text)Pass if doesn't match visible and "alt" text assertLink($label)Pass if a link with this text is present @@ -217,10 +214,7 @@ class TestOfLastcraft extends WebTestCase { assertHeader($header, $content)Pass if a header was fetched matching this value -assertNoUnwantedHeader($header)Pass if a header was not fetched - - -assertHeaderPattern($header, $pattern)Pass if a header was fetched matching this Perl regex +assertNoHeader($header)Pass if a header was not fetched assertCookie($name, $value)Pass if there is currently a matching cookie @@ -240,6 +234,10 @@ class TestOfLastcraft extends WebTestCase { So now we could instead test against the title tag with...
     $this->assertTitle('The Last Craft? Web developer tutorials on PHP, Extreme programming and Object Oriented development');
    +
    + ...or, if that is too long and fragile... +
    +$this->assertTitle(new PatternExpectation('/The Last Craft/'));
     
    As well as the simple HTML content checks we can check that the MIME type is in a list of allowed types with... @@ -319,7 +317,7 @@ class TestOfLastcraft extends WebTestCase { function testContact() { $this->get('http://www.lastcraft.com/'); $this->clickLink('About'); - $this->assertTitle('About Last Craft'); + $this->assertTitle(new PatternExpectation('/About Last Craft/')); } } @@ -327,10 +325,15 @@ class TestOfLastcraft extends WebTestCase {

    If the target is a button rather than an anchor tag, then - clickSubmit() should be used + clickSubmit() can be used with the button title...

     $this->clickSubmit('Go!');
    +
    + If you are not sure or don't care, the usual case, then just + use the click() method... +
    +$this->click('Go!');
     

    -- cgit v1.2.3