Author: maksim_ka
Date: 2010-05-24 13:16:35 +0200 (Mon, 24 May 2010)
New Revision: 29598

Modified:
   plugins/sfPhpunitPlugin/branches/1.2-4/README
Log:
[sfPhpunitPlugin] the doc for next package. finalization.

Modified: plugins/sfPhpunitPlugin/branches/1.2-4/README
===================================================================
--- plugins/sfPhpunitPlugin/branches/1.2-4/README       2010-05-24 06:00:11 UTC 
(rev 29597)
+++ plugins/sfPhpunitPlugin/branches/1.2-4/README       2010-05-24 11:16:35 UTC 
(rev 29598)
@@ -133,6 +133,8 @@
 The same is right for test case classes.
 Let's look at the BasePhpunitTestSuite.php in test/phpunit folder. Pay 
attenteion to _start and _end methods. You have to use them.
 
+    <?php
+  
     class BasePhpunitTestSuite extends sfBasePhpunitTestSuite
       implements sfPhpunitContextInitilizerInterface
     {
@@ -172,6 +174,8 @@
 So all tests that are running will have a context with application 'frontend' 
and environment 'test'.
 You can change it modifing the file.
 
+    <?php
+
     class BasePhpunitTestSuite extends sfBasePhpunitTestSuite
       implements sfPhpunitContextInitilizerInterface
     {
@@ -197,33 +201,611 @@
 
 ### Fixtures
 
-#### Basic workflow
+Very important thing in testing process is fixture managing. 
+It takes half time from all the test to create good environment. 
+So a good mechanism to work with them can save a lot of time. 
+Also it helps to keep tests simple and easy to understand.
 
-#### Fixture aggregators
+There is four places where you can keep your fixtures. 
+You can use all of them or just one.
 
-#### Fixture implementation
+*    Own - Fixtures from this directory can be used only be the current 
(executing) test. 
+*    Package - Fixtures from this directory can be used only be tests from the 
same directory.
+*    Common - Fixtures from this directory can be used from every test case.
+*    Symfony - Fixtures from this directory stored in standart symfony folder 
(data/fixtures) and can be used from every test case.
+   
+First of all you need to choose which fixtures you will use. 
+There are two types currently avalable:
 
+*    Doctrine 
+*    Propel
+
+It's simple example how to define a fixture type you want to use. 
+As you can see it is very easy to tell what you want to use. 
+You have to implement one of the following interfaces to a testcase class.
+
+    <?php
+
+    class FooTestCase extends PHPUnit_Framework_TestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function getPackageFixtureDir()
+      {
+        // implement this method 
+      }
+
+      public function getOwnFixtureDir()
+      {
+        // implement this method
+      }
+  
+      public function getCommonFixtureDir()
+      {
+        // implement this method
+      }
+
+      public function getSymfonyFixtureDir()
+      {
+        // implement this method
+      }
+      
+      public function testFoo()
+      {
+        // create fixture object by hands:
+        $fixture = sfPhpunitFixture::build($this, $options = array());
+        
+        //now you can use fixture instance to work with fixtures.
+        $path = $fixture->getFileOwn('fixture-file.txt');
+      
+        // test code here
+      }
+    }
+ 
+After you finish with this and run this test case you will see something like 
that:
+
+    >> phpunit   Created dir /home/maksim/projec...s/FooTestCase
+    >> phpunit   Created dir /home/maksim/projec...s/FooTestCase
+    PHPUnit 3.4.12 by Sebastian Bergmann.
+
+    .
+
+    Time: 7 seconds, Memory: 37.00Mb
+
+    OK (1 test, 8 assertions)
+    
+It is init task helps you with directories for fixture storing.
+It creates package and own directory if they are not exist.
+
+If you don't want to do even defining methods manualy you can 
+extends from sfBasePhpunitTestCase (where all that methods are already 
implemented) and implement interface.
+sfBasePhpunitTestCase also contain fixture method which returns instance of 
fixture so you need not create it manually. 
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      { 
+        $path = $this->fixture()->getFileOwn('fixture-file.txt');
+      
+        // test code here
+      }
+    }
+    
+In this case you get standart plugin fixture directories.
+Whole fixture directories are subdirectory of 
sf_root_dir/test/phpunit/fixtures dir.
+You can always overwrite any of that methods.
+   
+Let's say we have FooTestCase.php file in sf_root_dir/test/phpunit/units 
directory.
+Standart directories for the testcase will be:
+
+*    Own - sf_root_dir/test/phpunit/fixtures/units/FooTestCase
+*    Package - sf_root_dir/test/phpunit/fixtures/units
+*    Common - sf_root_dir/test/phpunit/fixtures/common
+*    Symfony - sf_root_dir/data/fixture
+
+#### File fixtures
+
+This example show you how to get path to file stored in fixture direcoties.
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $path = $this->fixture()->getFileOwn('foo.zip');
+        // result: sf_root_dir/test/phpunit/fixtures/units/FooTestCase/foo.zip
+        
+        $path = $this->fixture()->getFilePackage('foo.zip');
+        // result: sf_root_dir/test/phpunit/fixtures/units/foo.zip
+        
+        $path = $this->fixture()->getFileCommon('foo.zip');
+        // result: sf_root_dir/test/phpunit/fixtures/common/foo.zip
+        
+        $path = $this->fixture()->getFileSymfony('foo.zip');
+        // result: sf_root_dir/data/fixture/foo.zip
+      }
+    }
+        
+If the file does not exist exception will be thrown.
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $path = $this->fixture()->getFileOwn('not-exist-file.zip');
+        // result: exception is thrown.
+      }
+    }
+
+The same idea works for directories as well: 
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $path = $this->fixture()->getDirOwn();
+        // result: sf_root_dir/test/phpunit/fixtures/units/FooTestCase
+      }
+    }
+
+#### Database fixtures
+
+You can even load fixtures to the database. The database fixtures file is 
standart propel\doctrine fixture files.
+Loads users.doctrine.yml to the database.
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $path = $this->fixture()->loadOwn('users');
+        // load next file: 
sf_root_dir/test/phpunit/fixtures/units/FooTestCase/users.doctrine.yml
+        
+        $path = $this->fixture()->loadPackage('users');
+        // load next file: 
sf_root_dir/test/phpunit/fixtures/units/users.doctrine.yml
+        
+        $path = $this->fixture()->loadCommon('users');
+        // load next file: 
sf_root_dir/test/phpunit/fixtures/common/users.doctrine.yml
+        
+        $path = $this->fixture()->loadSymfony('users');
+        // load next file: sf_root_dir/data/fixture/users.doctrine.yml
+      }
+    }
+
+As you see you need not to give a file extension.
+The same for propel but extension will be *.propel.yml.    
+If the file does not exist exception will be thrown.
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $this->fixture()->loadOwn('not-exist-fixtures');
+        // result: exception is thrown.
+      }
+    }
+    
+For loadOwn, loadPackage, loadCommon, loadSymfony methods plugin supports 
[fluent interface](http://en.wikipedia.org/wiki/Fluent_interface)
+So you can do something like this:
+
+    <?php
+  
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $this->fixture()
+          ->loadOwn('users')
+          ->loadCommon('posts')
+          ->loadPackage('comments');
+      }
+    }
+    
+To clean the whole database and load new fixtures:
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $this->fixture()
+          ->clean()
+          // remove all data from the test database
+          ->loadOwn('users');
+          // only users will be in the database
+      }
+    }
+
+#### Snapshots
+
+It is very important to keep speed of the testing as fast as posible. 
+Yml fixture loading is expensive operation and can slow down your testing.
+To avoid this you can use snapshot feature.
+
+And second thing where snapshots can be usefull to group some fixtures file 
under single name, load all of them using this name.
+
+For example you can create some snapshots in root test suite and use them in 
any test case.
+
+    <?php
+    
+    class BasePhpunitTestSuite extends sfBasePhpunitTestSuite 
+      implements sfPhpunitFixturePropelAggregator
+    {
+      /**
+       * Dev hook for custom "setUp" stuff
+       */
+      protected function _start()
+      {          
+        $this->fixture()
+          ->clean()
+          
+          // clean up tables used for storing snapshot data.          
+          ->cleanSnapshots()
+          
+          ->loadCommon('users')
+          ->loadCommon('categories')
+          ->loadCommon('customers')
+            
+          ->doSnapshot('common');
+      }
+    }
+    
+Then load the snapshot in FooTestCase for example.
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        $this->fixture()->clean()->loadSnapshot('common);
+        
+        //and some additional stuff if needed.
+        $this->fixture()->loadCommon('comments');
+        // load fixtures form file 
sf_root_dir/data/fixture/comments.doctrine.yml
+          
+        // test code here.
+      }
+    }
+
+To clean all snapshots use method 
+
+    $this->fixture()->cleanSnapshots();
+    
+It is better group fixtures to snapshots and used them because it works it is 
kept and loaded in mysql and so works very fast.
+
+#### Customizing fixtures
+
+Fixture object can be init with some options. like file extension and database 
connection (by default it is taken from the sfContext).
+
+In future it can be done through the phpunit.yml but right now you have to 
rewrite _initFixture method:
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      protected function _initFixture(array $options = array())
+      {
+        $options = array(
+          'connection' => 'your connection',
+          'fixture_ext' => 'your database fixture extension. just *.yml for 
example',
+          'snapshot-table-prefix' => 'the table prefix used for snapshots',
+        );
+        
+        return parent::_initFixture($options);
+      }
+    }
+    
+#### ORM objects and database fixtures.
+
+This feature allows you to get Doctrine\Propel data object by its name in 
fixture file.
+For examlpe we have users.doctrine.yml file in the common fixture directory:
+
+    sfGuardUser:
+      TestUser:
+        username: user
+        password: test
+      RegistredUser2:
+        username: Lorne
+        password: Green    
+      sgu_admin:
+        username:       admin
+        password:       test
+        is_super_admin: true
+        
+And how it wotks in test case:
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+      implements sfPhpunitFixtureDoctrineAggregator
+      // for propel
+      //implements sfPhpunitFixturePropelAggregator
+    {
+      public function testFoo()
+      {
+        // loads users from 
sf_root_dir/test/phpunit/fixtures/common/users.doctrine.yml
+        $this->fixture()->clean()->loadCommon('users);
+        
+        // using method method get
+        $testUser = $this->fixture()->get('sfGuardUser_TestUser');
+        $this->assertType('sfGuardUser', $testUser);
+        
+        //shorter version
+        $registeredUser = $this->fixture('sfGuardUser_RegistredUser2');
+        $this->assertType('sfGuardUser', $registeredUser);
+      }
+    }      
+    
+This functionallity wotks perfectly with propel. For doctrine there are some 
bugs known.
+      
 ### Custom TestCases
 
+This test cases are not nessesary to be used but can be helpful for you.
+
 #### Selenium
 
+The sfBasePhpunitSeleniumTestCase class is extension of 
PHPUnit_Extensions_SeleniumTestCase standart phpunit class. 
+It allows you set options of a selenium server in phpunit.yml file and they 
will be handled automaticaly by sfBasePhpunitSeleniumTestCase class.
+
+The selenium section of phpunit.yml config: 
+    
+    all:
+      selenium:
+        remote_project_dir:
+        #you can used it in case of the test application and selenium server 
are run on different computers.
+        #but you have to upload the file stored in fixtures through web page.
+        #You need to mount prj dir to selenium computer and define this option.
+        #From the test case use for example method 
fixture()->getDirOwnAsRemote()
+        coverage: 
+          collect: false
+          coverageScript: phpunit_coverage.php        
+        driver:
+          name: false
+          browser: '*firefox'
+          browser_url: false
+          host: false
+          port: false
+          timeout: false
+          http_timeout: false
+          sleep: false
+          wait: false
+        
+Create your own phpunit.yml file in sf_root_dir/config for example and define 
yours own options there.
+The phpunit.yml files works the same as all other symfony configs (cascad, 
merging, project config dir, app config dir).
+
+The config can be look like:  
+
+    all:
+      selenium:
+        driver:
+          browser: '*chrome'
+          browser_url: 'http://google.com'
+          timeout: 10
+          http_timeout: 10
+          host: selenium-server.com
+
+And test:
+
+    class GoogleTestCase extends sfBasePhpunitSeleniumTestCase
+    {
+      protected function _start()
+      {
+        //$this->setAutoStop(false);
+        $this->start();
+        $this->open('/');
+        $this->windowMaximize();
+      }
+      
+      public function testGoogle()
+      {
+        // your google test here
+      }
+    }
+    
 #### Amf
 
-#### Unit
+The plugin also contains sfBasePhpunitAmfTestCase class for testing your 
[AMF](http://en.wikipedia.org/wiki/Action_Message_Format) services.
+It depends on [SabreAMF](http://code.google.com/p/sabreamf/downloads/list) 
library. 
+So you have to be sure you install it before.
 
-### Custom TestSuits
+It is a kind of functional tests becuase it emulates flex client and sends 
data throught the lan using http protocol.
 
-### Initialization
+First of you need to set a amfendpoint in phpunit.yml. 
+It highly recommended to make test in the same project (run test and send 
request on this server).
 
-### TestCase generation
+    all:
+      amf:
+        endpoint: 'http://your-server.com/amfendpoint'
 
+##### Send request using _getClient method:
+      
+    class Amf_Service_ClientTestCase extends sfBasePhpunitAmfTestCase 
+      implements sfPhpunitFixturePropelAggregator
+    {
+      public function testNewClient()
+      {      
+        $service = 'Service_Test.testNewClient';
+        $params = array('test');  
+      
+        $response = $this->_getClient()->sendRequest($serviceName, $params);
+        
+        // test response from the service
+      }
+
+##### Send request using helper class sfPhpunitAmfService. 
+
+The example do same as above:
+
+    class Amf_Service_ClientTestCase extends sfBasePhpunitAmfTestCase 
+      implements sfPhpunitFixturePropelAggregator
+    {
+    
+      // define a service name
+      protected $_amfservice = 'Service_Test';
+    
+      public function testNewClient()
+      {      
+        // testNewClient is handled by __call method. 
+        // It call Service_Test.testNewClient with one param 'test'
+        $response = $this->service()->testNewClient('test');
+        
+        // test response from the service
+      }
+    }
+    
+##### AMF Data Mapping 
+    
+If you use AMF data mapping this method can be very helpful for you. 
+Rewrite it keeping in mind the order of array parameters:
+
+    class Amf_Service_ClientTestCase extends sfBasePhpunitAmfTestCase 
+      implements sfPhpunitFixturePropelAggregator
+    {
+      public function testNewClient()
+      {      
+        // your amf test
+      }
+
+      protected function _getMappedClasses()
+      {
+        // array('flex_class' => 'php_class');
+        return array('ClientFlex' => 'ClientPHP');
+      }
+    }
+
+### Stubs data
+
+The sfBasePhpunitAmfTestCase class contain helpful method getStub. 
+It can be used only for stubs object.
+The method has the same interface as getMock method.
+
+This method allows you to create stubs objects simplier then getMock method:
+
+Compare this two ways:
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+    {
+      public function testFoo()
+      { 
+        $stub = $this->getMock('DataManager', array('getFoo', 'getBar'));
+        
$stub->expects($this->any())->method('getFoo')->will($this->returnValue('foo'));
+        
$stub->expects($this->any())->method('getBar')->will($this->returnValue('bar'));
+      
+        // test code here
+      }
+    }
+  
+and:
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+    {
+      public function testFoo()
+      { 
+        $stub = $this->getStub('DataManager', array(
+          'getFoo' => 'foo', 
+          'getBar' => 'bar'));
+      
+        // test code here
+      }
+    }
+
+getStub method used $this->any() method to set numbers of the stubed methods 
called. 
+You can use more strict version of this method:
+  
+    $this->getStubStrict( ... );
+    
+This method used $this->atLeastOnce(),
+
+If you need create two stubs with cross referance to each other. The next way 
can help:
+
+    <?php
+
+    class FooTestCase extends sfBasePhpunitTestCase 
+    {
+      public function testFoo()
+      { 
+        $stubFoo = $this->getStub('Foo', array('getBar' => 
$this->stubLater()));
+        $stubBar = $this->getStub('Bar', array('getFoo' => $stubFoo));
+        
+        $stubFoo->expects($this->any())->method('getBar' => $stubBar);
+      
+        // test code here
+      }
+    }
+
+### Good practices
+
+#### Use a diferent database for testing and dev (prod the same idea):
+    
+    test:
+      doctrine:
+        param:
+          dsn:      mysql:host=127.0.0.1;dbname=project_test
+          #dsn:     sqlite:////file_to/test.db?mode=0666
+          #dsn: "sqlite::memory:"
+
+    all:
+      doctrine:
+        class: sfDoctrineDatabase
+        param:
+          dsn:      mysql:host=127.0.0.1;dbname=project
+          username: mysqluser
+          password: mysqlpass
+
 ### Plans
 
 * Finish DbUnit fixture
 * fix autoloading bug in AllTests.php
 * several drivers for selenium
 * form testing
-* fix retriving objects by fixture name
+* fix retriving objects by fixture name (doctrine)
 * More inteligent init task
+* move models directory to units one
+* fixture options to phpunit.yml config.
+* standart phpunit config in phpunit.yml.
+* fresh sfConfig for each test case. 
 
 ### Feedback
\ No newline at end of file

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to