SuiteManager.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <?php
  2. namespace Codeception;
  3. use Codeception\Lib\Di;
  4. use Codeception\Lib\GroupManager;
  5. use Codeception\Lib\ModuleContainer;
  6. use Codeception\Lib\Notification;
  7. use Codeception\Test\Interfaces\ScenarioDriven;
  8. use Codeception\Test\Loader;
  9. use Codeception\Test\Descriptor;
  10. use Symfony\Component\EventDispatcher\EventDispatcher;
  11. class SuiteManager
  12. {
  13. public static $environment;
  14. public static $name;
  15. /**
  16. * @var \PHPUnit_Framework_TestSuite
  17. */
  18. protected $suite = null;
  19. /**
  20. * @var null|\Symfony\Component\EventDispatcher\EventDispatcher
  21. */
  22. protected $dispatcher = null;
  23. /**
  24. * @var GroupManager
  25. */
  26. protected $groupManager;
  27. /**
  28. * @var Loader
  29. */
  30. protected $testLoader;
  31. /**
  32. * @var ModuleContainer
  33. */
  34. protected $moduleContainer;
  35. /**
  36. * @var Di
  37. */
  38. protected $di;
  39. protected $tests = [];
  40. protected $debug = false;
  41. protected $path = '';
  42. protected $printer = null;
  43. protected $env = null;
  44. protected $settings;
  45. public function __construct(EventDispatcher $dispatcher, $name, array $settings)
  46. {
  47. $this->settings = $settings;
  48. $this->dispatcher = $dispatcher;
  49. $this->di = new Di();
  50. $this->path = $settings['path'];
  51. $this->groupManager = new GroupManager($settings['groups']);
  52. $this->moduleContainer = new ModuleContainer($this->di, $settings);
  53. $modules = Configuration::modules($this->settings);
  54. foreach ($modules as $moduleName) {
  55. $this->moduleContainer->create($moduleName);
  56. }
  57. $this->moduleContainer->validateConflicts();
  58. if (isset($settings['current_environment'])) {
  59. $this->env = $settings['current_environment'];
  60. }
  61. $this->suite = $this->createSuite($name);
  62. }
  63. public function initialize()
  64. {
  65. $this->dispatcher->dispatch(Events::MODULE_INIT, new Event\SuiteEvent($this->suite, null, $this->settings));
  66. foreach ($this->moduleContainer->all() as $module) {
  67. $module->_initialize();
  68. }
  69. if ($this->settings['actor'] && !file_exists(Configuration::supportDir() . $this->settings['actor'] . '.php')) {
  70. throw new Exception\ConfigurationException(
  71. $this->settings['actor']
  72. . " class doesn't exist in suite folder.\nRun the 'build' command to generate it"
  73. );
  74. }
  75. $this->dispatcher->dispatch(Events::SUITE_INIT, new Event\SuiteEvent($this->suite, null, $this->settings));
  76. ini_set('xdebug.show_exception_trace', 0); // Issue https://github.com/symfony/symfony/issues/7646
  77. }
  78. public function loadTests($path = null)
  79. {
  80. $testLoader = new Loader($this->settings);
  81. $testLoader->loadTests($path);
  82. $tests = $testLoader->getTests();
  83. if ($this->settings['shuffle']) {
  84. shuffle($tests);
  85. }
  86. foreach ($tests as $test) {
  87. $this->addToSuite($test);
  88. }
  89. $this->suite->reorderDependencies();
  90. }
  91. protected function addToSuite($test)
  92. {
  93. $this->configureTest($test);
  94. if ($test instanceof \PHPUnit_Framework_TestSuite_DataProvider) {
  95. foreach ($test->tests() as $t) {
  96. $this->addToSuite($t);
  97. }
  98. return;
  99. }
  100. if ($test instanceof TestInterface) {
  101. $this->checkEnvironmentExists($test);
  102. if (!$this->isExecutedInCurrentEnvironment($test)) {
  103. return; // skip tests from other environments
  104. }
  105. }
  106. $groups = $this->groupManager->groupsForTest($test);
  107. $this->suite->addTest($test, $groups);
  108. if (!empty($groups) && $test instanceof TestInterface) {
  109. $test->getMetadata()->setGroups($groups);
  110. }
  111. }
  112. protected function createSuite($name)
  113. {
  114. $suite = new Suite();
  115. $suite->setBaseName(preg_replace('~\s.+$~', '', $name)); // replace everything after space (env name)
  116. if ($this->settings['namespace']) {
  117. $name = $this->settings['namespace'] . ".$name";
  118. }
  119. $suite->setName($name);
  120. if (isset($this->settings['backup_globals'])) {
  121. $suite->setBackupGlobals((bool) $this->settings['backup_globals']);
  122. }
  123. if (isset($this->settings['be_strict_about_changes_to_global_state']) && method_exists($suite, 'setbeStrictAboutChangesToGlobalState')) {
  124. $suite->setbeStrictAboutChangesToGlobalState((bool)$this->settings['be_strict_about_changes_to_global_state']);
  125. }
  126. $suite->setModules($this->moduleContainer->all());
  127. return $suite;
  128. }
  129. public function run(PHPUnit\Runner $runner, \PHPUnit_Framework_TestResult $result, $options)
  130. {
  131. $runner->prepareSuite($this->suite, $options);
  132. $this->dispatcher->dispatch(Events::SUITE_BEFORE, new Event\SuiteEvent($this->suite, $result, $this->settings));
  133. $runner->doEnhancedRun($this->suite, $result, $options);
  134. $this->dispatcher->dispatch(Events::SUITE_AFTER, new Event\SuiteEvent($this->suite, $result, $this->settings));
  135. }
  136. /**
  137. * @return \Codeception\Suite
  138. */
  139. public function getSuite()
  140. {
  141. return $this->suite;
  142. }
  143. /**
  144. * @return ModuleContainer
  145. */
  146. public function getModuleContainer()
  147. {
  148. return $this->moduleContainer;
  149. }
  150. protected function getActor()
  151. {
  152. if (!$this->settings['actor']) {
  153. return null;
  154. }
  155. return $this->settings['namespace']
  156. ? rtrim($this->settings['namespace'], '\\') . '\\' . $this->settings['actor']
  157. : $this->settings['actor'];
  158. }
  159. protected function checkEnvironmentExists(TestInterface $test)
  160. {
  161. $envs = $test->getMetadata()->getEnv();
  162. if (empty($envs)) {
  163. return;
  164. }
  165. if (!isset($this->settings['env'])) {
  166. Notification::warning("Environments are not configured", Descriptor::getTestFullName($test));
  167. return;
  168. }
  169. $availableEnvironments = array_keys($this->settings['env']);
  170. $listedEnvironments = explode(',', implode(',', $envs));
  171. foreach ($listedEnvironments as $env) {
  172. if (!in_array($env, $availableEnvironments)) {
  173. Notification::warning("Environment $env was not configured but used in test", Descriptor::getTestFullName($test));
  174. }
  175. }
  176. }
  177. protected function isExecutedInCurrentEnvironment(TestInterface $test)
  178. {
  179. $envs = $test->getMetadata()->getEnv();
  180. if (empty($envs)) {
  181. return true;
  182. }
  183. $currentEnvironments = explode(',', $this->env);
  184. foreach ($envs as $envList) {
  185. $envList = explode(',', $envList);
  186. if (count($envList) == count(array_intersect($currentEnvironments, $envList))) {
  187. return true;
  188. }
  189. }
  190. return false;
  191. }
  192. /**
  193. * @param $t
  194. * @throws Exception\InjectionException
  195. */
  196. protected function configureTest($t)
  197. {
  198. if (!$t instanceof TestInterface) {
  199. return;
  200. }
  201. $t->getMetadata()->setServices([
  202. 'di' => clone($this->di),
  203. 'dispatcher' => $this->dispatcher,
  204. 'modules' => $this->moduleContainer
  205. ]);
  206. $t->getMetadata()->setCurrent([
  207. 'actor' => $this->getActor(),
  208. 'env' => $this->env,
  209. 'modules' => $this->moduleContainer->all()
  210. ]);
  211. if ($t instanceof ScenarioDriven) {
  212. $t->preload();
  213. }
  214. }
  215. }