44
55class Randomizer
66{
7- /**
8- * Order the TestSuite tests in a random order.
9- *
10- * @param \PHPUnit_Framework_Test $suite The suite to randomize.
11- * @param integer $seed Seed used for PHP to randomize the suite.
12- * @return \PHPUnit_Framework_Test
13- */
14- public function randomizeTestSuite (\PHPUnit_Framework_Test $ suite , $ seed )
15- {
7+ /**
8+ * Order the TestSuite tests in a random order.
9+ *
10+ * @param \PHPUnit_Framework_Test $suite The suite to randomize.
11+ * @param integer $seed Seed used for PHP to randomize the suite.
12+ * @return \PHPUnit_Framework_Test
13+ */
14+ public function randomizeTestSuite (\PHPUnit_Framework_Test $ suite , $ seed )
15+ {
1616 if ($ this ->testSuiteContainsOtherSuites ($ suite ))
1717 {
1818 $ this ->randomizeSuiteThatContainsOtherSuites ($ suite , $ seed );
1919 }
2020 else
2121 {
22- $ this ->randomizeSuite ($ suite , $ seed );
22+ $ this ->randomizeSuite ($ suite , $ seed, 0 );
2323 }
2424
2525 return $ suite ;
26- }
27-
28- /**
29- * Randomize each Test Suite inside the main Test Suite.
30- *
31- * @param [type] $suite Main Test Suite to randomize.
32- * @param [type] $seed Seed to use.
33- * @return \PHPUnit_Framework_Test
34- */
35- private function randomizeSuiteThatContainsOtherSuites ($ suite , $ seed )
26+ }
27+
28+ /**
29+ * Randomize each Test Suite inside the main Test Suite.
30+ *
31+ * @param [type] $suite Main Test Suite to randomize.
32+ * @param [type] $seed Seed to use.
33+ * @return \PHPUnit_Framework_Test
34+ */
35+ private function randomizeSuiteThatContainsOtherSuites ($ suite , $ seed )
3636 {
3737 $ order = 0 ;
3838 foreach ($ suite ->tests () as $ test ) {
3939 $ this ->randomizeSuite ($ test , $ seed , $ order );
4040 $ order ++;
4141 }
42-
43- return $ this ->randomizeSuite ($ suite , $ seed , $ order );
42+ return $ this ->randomizeSuite ($ suite , $ seed , $ order , false );
4443 }
4544
4645 /**
4746 * Test Suites can contain other Test Suites or just Test Cases.
48- *
47+ *
4948 * @param \PHPUnit_Framework_Test $suite [description]
5049 * @return Boolean
5150 */
@@ -57,34 +56,135 @@ private function testSuiteContainsOtherSuites($suite)
5756
5857 /**
5958 * Randomize the test cases inside a TestSuite, with the given seed.
60- *
61- * @param \PHPUnit_Framework_Test $suite Test suite to randomize.
62- * @param integer $seed Seed to be used for the random funtion.
63- * @param integer $order Arbitrary value to "salt" the seed.
59+ *
60+ * @param \PHPUnit_Framework_Test $suite Test suite to randomize.
61+ * @param integer $seed Seed to be used for the random funtion.
62+ * @param integer $order Arbitrary value to "salt" the seed.
63+ * @param bool $fix_depends [=false]
6464 * @return \PHPUnit_Framework_Test
6565 */
66- private function randomizeSuite ($ suite , $ seed , $ order = 0 )
66+ private function randomizeSuite ($ suite , $ seed , $ order = 0 , $ fix_depends = true )
6767 {
6868 $ reflected = new \ReflectionObject ($ suite );
6969 $ property = $ reflected ->getProperty ('tests ' );
7070 $ property ->setAccessible (true );
71- $ property ->setValue ($ suite , $ this ->randomizeTestsCases ($ suite ->tests (), $ seed , $ order ));
71+ $ property ->setValue ($ suite , $ this ->randomizeTestsCases ($ suite ->tests (), $ seed , $ order, $ fix_depends ));
7272
7373 return $ suite ;
7474 }
7575
7676 /**
7777 * Randomize an array of TestCases.
7878 *
79- * @param array $tests TestCases to randomize.
80- * @param integer $seed Seed used for PHP to randomize the array.
81- * @param integer $order A salt so it doesn't randomize all the classes in the same "random" order.
82- * @return array Randomized array
79+ * @param array $tests TestCases to randomize.
80+ * @param integer $seed Seed used for PHP to randomize the array.
81+ * @param integer $order A salt so it doesn't randomize all the classes in the same "random" order.
82+ * @param bool $fix_depends [=false]
83+ * @return array Randomized array
8384 */
84- private function randomizeTestsCases (array $ tests , $ seed , $ order )
85+ private function randomizeTestsCases (array $ tests , $ seed , $ order, $ fix_depends = false )
8586 {
8687 srand ($ seed + $ order );
8788 shuffle ($ tests );
88- return $ tests ;
89+ return $ fix_depends ? $ this ->fixDependencies ($ tests ) : $ tests ;
90+ }
91+
92+ /**
93+ * fix tests order because of @depends annotations
94+ *
95+ * @param array $tests TestCases to randomize.
96+ * @return array Fixed randomized array
97+ */
98+ private function fixDependencies (array $ tests )
99+ {
100+ $ tests_dependencies = $ tests_methods = [];
101+
102+ foreach ($ tests as $ i => $ test ) {
103+ $ reflected = new \ReflectionObject ($ test );
104+ $ name_field = $ dependencies_field = null ;
105+
106+ while ($ reflected = $ reflected ->getParentClass ()) {
107+ try {
108+ if (empty ($ dependencies_field )) {
109+ $ dependencies_field = $ reflected ->getProperty ('dependencies ' );
110+ $ dependencies_field ->setAccessible (true );
111+ }
112+ if (empty ($ name_field )) {
113+ $ name_field = $ reflected ->getProperty ('name ' );
114+ $ name_field ->setAccessible (true );
115+ }
116+ } catch (\ReflectionException $ e ){
117+ //do nothing
118+ }
119+ }
120+
121+ if (empty ($ name_field )) {
122+ return $ tests ;
123+ }
124+
125+ $ tests_methods [$ name_field ->getValue ($ test )] = $ i ;
126+
127+ if (empty ($ dependencies = $ dependencies_field ->getValue ($ test ))){
128+ continue ;
129+ }
130+ foreach ($ dependencies as $ dependency ) {
131+ $ tests_dependencies [$ name_field ->getValue ($ test )] = $ dependency ;
132+ }
133+ }
134+
135+ if (empty ($ tests_dependencies )) {
136+ return $ tests ;
137+ }
138+
139+ $ new_order = $ this ->setOrder ($ tests_dependencies , $ tests_methods );
140+ $ new_tests_order = [];
141+ foreach ($ new_order as $ test_name ) {
142+ $ new_tests_order [] = $ tests [$ tests_methods [$ test_name ]];
143+ }
144+
145+ return $ new_tests_order ;
146+ }
147+
148+ /**
149+ * preapare test methods required order
150+ *
151+ * @param array $tests_dependencies tests dependencies array
152+ * @param array $tests_methods tests (shuffled) array
153+ * @return array array
154+ */
155+ private function setOrder ($ tests_dependencies , $ tests_methods )
156+ {
157+ $ new_order = [];
158+ foreach ($ tests_methods as $ method_name => $ order ) {
159+ if (isset ($ tests_dependencies [$ method_name ]) && !in_array ($ tests_dependencies [$ method_name ], $ new_order )) {
160+ $ new_order [] = $ tests_dependencies [$ method_name ];
161+ $ this ->isDependant ($ new_order , $ tests_dependencies , $ tests_methods , $ tests_dependencies [$ method_name ]);
162+ }
163+
164+ if (!in_array ($ method_name , $ new_order )) {
165+ $ new_order [] = $ method_name ;
166+ }
167+ }
168+
169+ return $ new_order ;
170+ }
171+
172+ /**
173+ * check if dependant method has another dependant method (recursive)
174+ *
175+ * @param array $new_order tests fixed (shuflled, with dependencies) array
176+ * @param array $tests_dependencies tests dependencies array
177+ * @param array $tests_methods tests (shuffled) array
178+ * @return void
179+ */
180+ private function isDependant (&$ new_order , $ tests_dependencies , $ tests_methods , $ method )
181+ {
182+ foreach ($ tests_dependencies as $ dependant => $ depends ) {
183+ if ($ method == $ dependant && !in_array ($ depends , $ new_order )) {
184+ array_splice ($ new_order , array_search ($ method , $ new_order ), 0 , [$ depends ]);
185+ $ this ->isDependant ($ new_order , $ tests_dependencies , $ tests_methods , $ depends );
186+ }
187+ }
89188 }
189+
90190}
0 commit comments