From af68030fcf0c266300feb2c100149ecadef7d364 Mon Sep 17 00:00:00 2001 From: xue <> Date: Sun, 16 Jul 2006 01:50:23 +0000 Subject: Merge from 3.0 branch till 1264. --- .../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
+ 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
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 {
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
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
-<?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
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...Will fail as the variable $a is a copy of $b.-$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. +@@ -426,15 +540,6 @@ class LoggingSessionPoolTest extends UnitTestCase { You can have wildcards and sequences and the order of evaluation is the same. -+ 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);
- 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. - -Copyright
Marcus Baker, Jason Sweat, Perrick Penet 2004 diff --git a/tests/test_tools/simpletest/docs/en/overview.html b/tests/test_tools/simpletest/docs/en/overview.html index d4965de3..5d4e80e2 100755 --- a/tests/test_tools/simpletest/docs/en/overview.html +++ b/tests/test_tools/simpletest/docs/en/overview.html @@ -23,9 +23,6 @@ Group tests-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. - 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. -
@@ -163,12 +159,12 @@ class MySiteTest extends WebTestCase { Unit test case Core test case class and assertions -Done +1.0 Html display Simplest possible display -Done +1.0 Autoloading of test cases @@ -176,41 +172,20 @@ class MySiteTest extends WebTestCase { Reading a file with test cases and loading them into a group test automatically -Done +1.0 - -Mock objects code generator +Mock 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 - -Done +1.0 - Web test case -Basic pattern matching of fetched pages -Done -- HTML parsing of pages Allows link following and title tag matching -Done +1.0 Partial mocks @@ -218,32 +193,32 @@ class MySiteTest extends WebTestCase { Mocking parts of a class for testing less than a class or for complex simulations -Done +1.0 Web cookie handling Correct handling of cookies when fetching pages -Done +1.0 Following redirects Page fetching automatically follows 300 redirects -Done +1.0 Form parsing Ability to submit simple forms and read default form values -Done +1.0 Command line interface Test display without the need of a web browser -Done +1.0 Exposure of expectation classes Can create precise tests with mocks as well as test cases -Done +1.0 XML output and parsing @@ -251,25 +226,15 @@ class MySiteTest extends WebTestCase { Allows multi host testing and the integration of acceptance testing extensions -Done +1.0 - -Command line test case -Allows testing of utilities and file handling -Done -- -PHP Documentor compatibility -Fully generated class level documentation -Done -- Browser interface +Browser component Exposure of lower level web browser interface for more detailed test cases -Done +1.0 - HTTP authentication @@ -277,31 +242,39 @@ class MySiteTest extends WebTestCase { Fetching protected web pages with basic authentication only -Done -- Browser navigation buttons -Back, forward and retry -Done +1.0 SSL support Can connect to https: pages -Done +1.0 Proxy support Can connect via. common proxies -Done +1.0 + Frames support Handling of frames in web test cases -Done +1.0 ++ +File upload testing +Can simulate the input type file tag +1.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 display -Better web GUI with tree display of test cases +Reporting machinery enhancements +Improved message passing for better cooperation with IDEs 1.1 @@ -310,28 +283,43 @@ class MySiteTest extends WebTestCase { 1.1 - File upload testing -Can simulate the input type file tag +Testing exceptions +Similar to testing PHP errors 1.1 - +Mocking interfaces -Can generate mock objects to interfaces as well as classes +IFrame support +Reads IFrame content that can be refreshed +1.1 ++ Improved mock interface +More compact way of expressing mocks 2.0 - +Testing exceptions -Similar to testing PHP errors +HTML table assertions +Can match table elements to numerical assertions +2.0 ++ XPath searching of HTML elements +More flexible content matching 2.0 - +XPath searching of elements -Can make use of HTML tidy for faster and more flexible content matching +Alternate HTML parsers +Can detect compiled parsers for performance improvements 2.0 + Javascript suport +Use of PECL module to add Javascript +3.0 +- 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 - @@ -226,7 +229,7 @@ $this->assertReference($a, $b);assertErrorPattern($p) Fail unless the error matches the regex $p +assertExpectation($e) Fail on failed expectation object -$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
$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