php - Behat scenario failing if run with other scenarios -


i have rather odd 1 here today...

i have behat feature file contains several scenarios. each of scenarios pass if run individually, if run feature file in it's entirety, 1 of tests fails, error...

notice: undefined index: 00000000070885f90000000106598262 in /project/vendor/doctrine/orm/lib/doctrine/orm/unitofwork.php line 2058 

... (shown below)

the scenarios load fixtures, , navigates around pages using information in fixture entity, , check page urls correct.

the weird thing second test fails, if first 1 run before it. if it's not, context manages store fixture entity property, , use entitymanager::merge() , entitymanager::refresh() reload entity it's current state. when first test run before it, context still fetching , storing fixture entity in same way, when attempts merge , refresh, reason entity manager unit of work seems have forgotten it.

before each scenario d/b cleared, , fixtures reloaded, using code shown below. i've made sure i've called entitymanager::clear() ensure remnants of previous test removed.

/**  * clears d/b  *  * @throws toolsexception  */ public function cleardb() {     foreach ($this->getentitymanagers() $entitymanager) {         $metadata = $this->getmetadata($entitymanager);         if (!empty($metadata)) {             $tool = new schematool($entitymanager);             $tool->dropschema($metadata);             $tool->createschema($metadata);         }     } } 

a bit more info investigation...

having investigated further, it's not problem if first test fetches entity, stores it, not request page (using mink)

files...

behat test (with annotations)

@fix:application\stage9submitted\submittedstage1 @fix:user\fundadmin\fundadmin1 scenario: can assign application case worker   given logged in "user\fundadmin\fundadmin1" fixture user   , on application admin "eligibility" page "application\stage9submitted\submittedstage1" fixture application       ^== fetches amd saves $currententity   , should see "unassigned" in ".application-summary .case-worker" element   when follow "change case worker"   , select "fund.admin@example.com" "project_application_admin_change_caseworker_caseworker"   , press "change case worker"   should on application admin "eligibility" page application       ^== retrieves $currententity , calls entitymanager::merge() , entitymanager::refresh()       ^== works    , should see "fund admin" in ".application-summary .case-worker span[title='fund.admin@example.com']" element   , should see "application assigned fund admin"   @fix:application\stage9submitted\submittedstage1 @fix:user\fundadmin\fundadmin1 scenario: can un-assign application case worker   given logged in "user\fundadmin\fundadmin1" fixture user   , on application admin "eligibility" page "application\stage9submitted\submittedstage1" fixture application       ^== fetches amd saves $currententity   , should see "unassigned" in ".application-summary .case-worker" element   , follow "change case worker"   , select "fund.admin@example.com" "project_application_admin_change_caseworker_caseworker"   , press "change case worker"   , should on application admin "eligibility" page application       ^== retrieves $currententity , calls entitymanager::merge() , entitymanager::refresh()       ^== fails (but if above test run @ same time!?!)   ... 

fixturescontext

<?php  namespace cubicmushroom\symfonyfeaturecontextbundle\feature\context;  use behat\behat\hook\scope\beforescenarioscope; use behat\symfony2extension\context\kernelawarecontext; use doctrine\common\datafixtures\abstractfixture; use doctrine\common\datafixtures\executor\ormexecutor; use doctrine\common\datafixtures\fixtureinterface; use doctrine\common\datafixtures\loader; use doctrine\common\datafixtures\purger\ormpurger; use doctrine\common\datafixtures\referencerepository; use doctrine\dbal\connection; use doctrine\orm\entitymanager; use doctrine\orm\tools\schematool; use doctrine\orm\tools\toolsexception; use project\datafixtures\orm\abstractsinglefixture; use project\exception\feature\context\fixturecontext\fixturenotfoundexception; use symfony\component\dependencyinjection\containerinterface; use symfony\component\httpkernel\kernelinterface;  /**  * loads fixtures based on scenario tags  *  * @package project  */ class fixturescontext implements kernelawarecontext {     // -----------------------------------------------------------------------------------------------------------------     // properties     // -----------------------------------------------------------------------------------------------------------------      /**      * @var kernelinterface      */     protected $kernel;      /**      * @var array      */     protected $fixturenamespaces;      /**      * @var loader      */     protected $loader;      /**      * @var abstractfixture[]      */     protected $loadedfixtures;      /**      * @var ormexecutor      */     protected $executor;       /**      * newfixturescontext constructor.      *      * @param array $fixturenamespaces      */     public function __construct(array $fixturenamespaces)     {         foreach ($fixturenamespaces $fixturenamespace) {             $this->addfixturenamespace($fixturenamespace);         }     }       // -----------------------------------------------------------------------------------------------------------------     // @beforescenario     // -----------------------------------------------------------------------------------------------------------------      /**      * @beforescenario      *      * @param beforescenarioscope $scope      */     public function loadfixturesfromtags(beforescenarioscope $scope)     {         // load here, rather in constructor it's re-initialised on each scenario         $this->loader = new loader();          $tags = $scope->getscenario()->gettags();          foreach ($tags $tag) {             $this->loadfixturesfortag($this->loader, $tag);         }          $fixtures = $this->loader->getfixtures();          if (empty($fixtures)) {             return;         }          $this->cleardb();          $em = $this->getentitymanager();         $em->clear();          $purger         = new ormpurger();         $this->executor = new ormexecutor($em, $purger);         $this->executor->purge();         $this->executor->execute($fixtures, true);          $this->loadedfixtures = $fixtures;     }       /**      * @param string $fixture      *      * @return array      */     public function getnamespacedfixtures($fixture)     {         $fixtures = [];          foreach ($this->fixturenamespaces $fixturenamespace) {              $fixtureclass = "{$fixturenamespace}\\{$fixture}";              if (class_exists($fixtureclass)) {                 $fixtures[] = $fixtureclass;             }         }          return $fixtures;     }       /**      * clears d/b      *      * @throws toolsexception      */     public function cleardb()     {         foreach ($this->getentitymanagers() $entitymanager) {             $metadata = $this->getmetadata($entitymanager);             if (!empty($metadata)) {                 $tool = new schematool($entitymanager);                 $tool->dropschema($metadata);                 $tool->createschema($metadata);             }         }     }       /**      * loads fixtures given tag      *      * @param loader $loader      * @param string $tag      */     protected function loadfixturesfortag(loader $loader, $tag)     {         $parts  = explode(':', $tag);         $prefix = array_shift($parts);          // bother tags staring 'fix:'         if ('fix' !== $prefix) {             return;         }          if (empty($parts)) {             throw new \logicexception('no fixture provided');         }          $fixture = array_shift($parts);         $args    = $parts;          $fixtureclasses = $this->getnamespacedfixtures($fixture);          foreach ($fixtureclasses $fixtureclass) {             $reflect  = new \reflectionclass($fixtureclass);             $instance = $reflect->newinstanceargs($args);              if (!$instance instanceof fixtureinterface) {                 throw new \invalidargumentexception("class {$fixtureclass} not implement fixtureinterface");             }              $loader->addfixture($instance);              return;         }          throw fixturenotfoundexception::create($fixture);     }       /**      * @afterscenario      *      *      * @return null      */     public function closedbalconnections()     {         /** @var entitymanager $entitymanager */         foreach ($this->getentitymanagers() $entitymanager) {             $entitymanager->clear();         }         /** @var connection $connection */         foreach ($this->getconnections() $connection) {             $connection->close();         }     }       // -----------------------------------------------------------------------------------------------------------------     // getters , setters     // -----------------------------------------------------------------------------------------------------------------       /**      * @param $fixturesdir      *      * @return $this      */     protected function addfixturenamespace($fixturesdir)     {         if (!isset($this->fixturenamespaces)) {             $this->fixturenamespaces = [];         }          if (!in_array($fixturesdir, $this->fixturenamespaces)) {             $this->fixturenamespaces[] = $fixturesdir;         }          return $this;     }       /**      * sets kernel instance.      *      * @param kernelinterface $kernel      */     public function setkernel(kernelinterface $kernel)     {         $this->kernel = $kernel;     }       /**      * @return containerinterface      */     protected function getcontainer()     {         return $this->kernel->getcontainer();     }       /**      * @param entitymanager $entitymanager      *      * @return array      */     protected function getmetadata(entitymanager $entitymanager)     {         return $entitymanager->getmetadatafactory()->getallmetadata();     }       /**      * @return array      */     protected function getentitymanagers()     {         return $this->getcontainer()->get('doctrine')->getmanagers();     }       /**      * @return entitymanager      */     protected function getentitymanager()     {         $em = $this->kernel->getcontainer()->get('doctrine.orm.entity_manager');          return $em;     }       /**      * @return connection[]      */     protected function getconnections()     {         return $this->kernel->getcontainer()->get('doctrine')->getconnections();     }       /**      * @return ormexecutor      */     public function getexecutor()     {         return $this->executor;     }       /**      * @return referencerepository      */     public function getreferencerepository()     {         return $this->executor->getreferencerepository();     }       /**      * @param string $fixtureclass      *      * @return fixtureinterface      *      * @throws \outofboundsexception if fixture not found      */     public function getfixture($fixtureclass)     {         try {             $userfixture = $this->_getfixture($fixtureclass);         } catch (\outofboundsexception $exception) {             $fixtures = $this->getnamespacedfixtures($fixtureclass);              if (empty($fixtures)) {                 throw new \outofboundsexception("fixture {$fixtureclass} not found");             }              if (count($fixtures) > 1) {                 throw new \logicexception(                     "found multiple {$fixtureclass} fixtures.  use full namespace correct"                 );             }              /** @var abstractsinglefixture $userfixture */             $userfixture = $this->_getfixture($fixtures[0]);         }          return $userfixture;     }       /**      * @param string $fixtureclass      *      * @return fixtureinterface      *      * @throws \outofboundsexception if fixture not found      */     protected function _getfixture($fixtureclass)     {         foreach ($this->loader->getfixtures() $fixture) {             if (is_a($fixture, $fixtureclass)) {                 return $fixture;             }         }          throw new \outofboundsexception("fixture '{$fixtureclass}' not found'");     }       /**      * @param $fixtureclass      *      * @return object      *      * @throw \outofboundsexception if fixture not found      */     public function getfixtureentity($fixtureclass)     {         // fixture class shorthand, without namespace, use getfixture full class name…         $fixture      = $this->getfixture($fixtureclass);         $fixtureclass = get_class($fixture);          $referencerepository = $this->getreferencerepository();          if (!$referencerepository->hasreference($fixtureclass)) {             throw new \outofboundsexception("fixture '{$fixtureclass}' not found");         }          return $referencerepository->getreference($fixtureclass);     } } 

unitofwork.php

# /project/vendor/doctrine/orm/lib/doctrine/orm/unitofwork.php showing line 2058 # (marked on rh side of code)  <?php  namespace doctrine\orm;  use ...  class unitofwork implements propertychangedlistener {      // ...      /**      * executes refresh operation on entity.      *      * @param object $entity  entity refresh.      * @param array  $visited visited entities during cascades.      *      * @return void      *      * @throws orminvalidargumentexception if entity not managed.      */     private function dorefresh($entity, array &$visited)     {         $oid = spl_object_hash($entity);          if (isset($visited[$oid])) {             return; // prevent infinite recursion         }          $visited[$oid] = $entity; // mark visited          $class = $this->em->getclassmetadata(get_class($entity));          if ($this->getentitystate($entity) !== self::state_managed) {             throw orminvalidargumentexception::entitynotmanaged($entity);         }          $this->getentitypersister($class->name)->refresh(             array_combine($class->getidentifierfieldnames(), $this->entityidentifiers[$oid]),      <===== line 2058             $entity         );          $this->cascaderefresh($entity, $visited);     }      // ... } 

i'll not post context classes here, if need more info, please let me know.

any or pointers appreciated.

many thanks.

probably scenarios aren't "teared down" correctly.

i have solutions problem:

1) slow approach

recreate db data (so, load fixtures basically) each time run new scenario

2) faster approach

run every scenario in transaction , discard changes after each scenario has finished

your tests should isolated , never affected other test runs before or after them.


Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -