Skip to content

Commit

Permalink
Merge pull request #19 from prymas007/master
Browse files Browse the repository at this point in the history
  • Loading branch information
fiunchinho authored Aug 3, 2016
2 parents 037832d + 3651818 commit f35935d
Showing 1 changed file with 135 additions and 35 deletions.
170 changes: 135 additions & 35 deletions src/PHPUnitRandomizer/Randomizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,47 @@

class Randomizer
{
/**
* Order the TestSuite tests in a random order.
*
* @param \PHPUnit_Framework_Test $suite The suite to randomize.
* @param integer $seed Seed used for PHP to randomize the suite.
* @return \PHPUnit_Framework_Test
*/
public function randomizeTestSuite(\PHPUnit_Framework_Test $suite, $seed)
{
/**
* Order the TestSuite tests in a random order.
*
* @param \PHPUnit_Framework_Test $suite The suite to randomize.
* @param integer $seed Seed used for PHP to randomize the suite.
* @return \PHPUnit_Framework_Test
*/
public function randomizeTestSuite(\PHPUnit_Framework_Test $suite, $seed)
{
if ($this->testSuiteContainsOtherSuites($suite))
{
$this->randomizeSuiteThatContainsOtherSuites($suite, $seed);
}
else
{
$this->randomizeSuite($suite, $seed);
$this->randomizeSuite($suite, $seed, 0);
}

return $suite;
}

/**
* Randomize each Test Suite inside the main Test Suite.
*
* @param [type] $suite Main Test Suite to randomize.
* @param [type] $seed Seed to use.
* @return \PHPUnit_Framework_Test
*/
private function randomizeSuiteThatContainsOtherSuites($suite, $seed)
}

/**
* Randomize each Test Suite inside the main Test Suite.
*
* @param [type] $suite Main Test Suite to randomize.
* @param [type] $seed Seed to use.
* @return \PHPUnit_Framework_Test
*/
private function randomizeSuiteThatContainsOtherSuites($suite, $seed)
{
$order = 0;
foreach ($suite->tests() as $test) {
$this->randomizeSuite($test, $seed, $order);
$order++;
}

return $this->randomizeSuite($suite, $seed, $order);
return $this->randomizeSuite($suite, $seed, $order, false);
}

/**
* Test Suites can contain other Test Suites or just Test Cases.
*
*
* @param \PHPUnit_Framework_Test $suite [description]
* @return Boolean
*/
Expand All @@ -57,34 +56,135 @@ private function testSuiteContainsOtherSuites($suite)

/**
* Randomize the test cases inside a TestSuite, with the given seed.
*
* @param \PHPUnit_Framework_Test $suite Test suite to randomize.
* @param integer $seed Seed to be used for the random funtion.
* @param integer $order Arbitrary value to "salt" the seed.
*
* @param \PHPUnit_Framework_Test $suite Test suite to randomize.
* @param integer $seed Seed to be used for the random funtion.
* @param integer $order Arbitrary value to "salt" the seed.
* @param bool $fix_depends [=false]
* @return \PHPUnit_Framework_Test
*/
private function randomizeSuite($suite, $seed, $order = 0)
private function randomizeSuite($suite, $seed, $order = 0, $fix_depends = true)
{
$reflected = new \ReflectionObject($suite);
$property = $reflected->getProperty('tests');
$property->setAccessible(true);
$property->setValue($suite, $this->randomizeTestsCases($suite->tests(), $seed, $order));
$property->setValue($suite, $this->randomizeTestsCases($suite->tests(), $seed, $order, $fix_depends));

return $suite;
}

/**
* Randomize an array of TestCases.
*
* @param array $tests TestCases to randomize.
* @param integer $seed Seed used for PHP to randomize the array.
* @param integer $order A salt so it doesn't randomize all the classes in the same "random" order.
* @return array Randomized array
* @param array $tests TestCases to randomize.
* @param integer $seed Seed used for PHP to randomize the array.
* @param integer $order A salt so it doesn't randomize all the classes in the same "random" order.
* @param bool $fix_depends [=false]
* @return array Randomized array
*/
private function randomizeTestsCases(array $tests, $seed, $order)
private function randomizeTestsCases(array $tests, $seed, $order, $fix_depends = false)
{
srand($seed + $order);
shuffle($tests);
return $tests;
return $fix_depends ? $this->fixDependencies($tests) : $tests;
}

/**
* fix tests order because of @depends annotations
*
* @param array $tests TestCases to randomize.
* @return array Fixed randomized array
*/
private function fixDependencies(array $tests)
{
$tests_dependencies = $tests_methods = [];

foreach ($tests as $i => $test) {
$reflected = new \ReflectionObject($test);
$name_field = $dependencies_field = null;

while ($reflected = $reflected->getParentClass()) {
try {
if (empty($dependencies_field)) {
$dependencies_field = $reflected->getProperty('dependencies');
$dependencies_field->setAccessible(true);
}
if (empty($name_field)) {
$name_field = $reflected->getProperty('name');
$name_field->setAccessible(true);
}
} catch (\ReflectionException $e ){
//do nothing
}
}

if (empty($name_field)) {
return $tests;
}

$tests_methods[$name_field->getValue($test)] = $i;

if (empty($dependencies = $dependencies_field->getValue($test))){
continue;
}
foreach ($dependencies as $dependency) {
$tests_dependencies[$name_field->getValue($test)] = $dependency;
}
}

if (empty($tests_dependencies)) {
return $tests;
}

$new_order = $this->setOrder($tests_dependencies, $tests_methods);
$new_tests_order = [];
foreach ($new_order as $test_name) {
$new_tests_order[] = $tests[$tests_methods[$test_name]];
}

return $new_tests_order;
}

/**
* preapare test methods required order
*
* @param array $tests_dependencies tests dependencies array
* @param array $tests_methods tests (shuffled) array
* @return array array
*/
private function setOrder($tests_dependencies, $tests_methods)
{
$new_order = [];
foreach ($tests_methods as $method_name => $order) {
if (isset($tests_dependencies[$method_name]) && !in_array($tests_dependencies[$method_name], $new_order)) {
$new_order[] = $tests_dependencies[$method_name];
$this->isDependant($new_order, $tests_dependencies, $tests_methods, $tests_dependencies[$method_name]);
}

if (!in_array($method_name, $new_order)) {
$new_order[] = $method_name;
}
}

return $new_order;
}

/**
* check if dependant method has another dependant method (recursive)
*
* @param array $new_order tests fixed (shuflled, with dependencies) array
* @param array $tests_dependencies tests dependencies array
* @param array $tests_methods tests (shuffled) array
* @return void
*/
private function isDependant(&$new_order, $tests_dependencies, $tests_methods, $method)
{
foreach ($tests_dependencies as $dependant => $depends) {
if ($method == $dependant && !in_array($depends, $new_order)) {
array_splice($new_order, array_search($method, $new_order), 0, [$depends]);
$this->isDependant($new_order, $tests_dependencies, $tests_methods, $depends);
}
}
}

}

0 comments on commit f35935d

Please sign in to comment.