Skip to content

Commit f35935d

Browse files
authored
Merge pull request #19 from prymas007/master
#10
2 parents 037832d + 3651818 commit f35935d

File tree

1 file changed

+135
-35
lines changed

1 file changed

+135
-35
lines changed

src/PHPUnitRandomizer/Randomizer.php

Lines changed: 135 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,47 @@
44

55
class 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

Comments
 (0)