New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@Depends file will be run if not ran yet + Full namespace bug when using @depends [FEATURE&BUG-FIX] #3449
@Depends file will be run if not ran yet + Full namespace bug when using @depends [FEATURE&BUG-FIX] #3449
Changes from 2 commits
6c50e02
3772bad
06a277e
64d6350
e4e33f2
9cd8d5d
2b5dbfd
6b37bd3
e53378d
2f58830
0d01999
7a95ba9
ef8ec3e
845d689
58d289d
c33a58a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1685,10 +1685,12 @@ private function verifyMockObjects(): void | |
private function handleDependencies(): bool | ||
{ | ||
if (!empty($this->dependencies) && !$this->inIsolation) { | ||
$className = \get_class($this); | ||
$passed = $this->result->passed(); | ||
$passedKeys = \array_keys($passed); | ||
$numKeys = \count($passedKeys); | ||
$className = \get_class($this); | ||
$passed = $this->result->passed(); | ||
$failed = $this->result->failures(); | ||
$skipped = $this->result->skipped(); | ||
$passedKeys = \array_keys($passed); | ||
$numKeys = \count($passedKeys); | ||
|
||
for ($i = 0; $i < $numKeys; $i++) { | ||
$pos = \strpos($passedKeys[$i], ' with data set'); | ||
|
@@ -1698,7 +1700,33 @@ private function handleDependencies(): bool | |
} | ||
} | ||
|
||
$passedKeys = \array_flip(\array_unique($passedKeys)); | ||
$failedKeys = []; | ||
|
||
foreach ($failed as $failure) { | ||
$pos = \strpos($failure->getTestName(), ' with data set'); | ||
|
||
if ($pos !== false) { | ||
$failedKeys[] = \substr($failure->getTestName(), 0, $pos); | ||
} else { | ||
$failedKeys[] = $failure->getTestName(); | ||
} | ||
} | ||
|
||
$skippedKeys = []; | ||
|
||
foreach ($skipped as $skip) { | ||
$pos = \strpos($skip->getTestName(), ' with data set'); | ||
|
||
if ($pos !== false) { | ||
$skippedKeys[] = \substr($skip->getTestName(), 0, $pos); | ||
} else { | ||
$skippedKeys[] = $skip->getTestName(); | ||
} | ||
} | ||
|
||
$passedKeys = \array_flip(\array_unique($passedKeys)); | ||
$failedKeys = \array_flip(\array_unique($failedKeys)); | ||
$skippedKeys = \array_flip(\array_unique($skippedKeys)); | ||
|
||
foreach ($this->dependencies as $dependency) { | ||
$deepClone = false; | ||
|
@@ -1724,31 +1752,54 @@ private function handleDependencies(): bool | |
$dependency = $className . '::' . $dependency; | ||
} | ||
|
||
if (\strpos($dependency, '\\') === 0) { | ||
$dependency = \substr($dependency, 1); | ||
} | ||
|
||
if (!isset($passedKeys[$dependency])) { | ||
$this->status = BaseTestRunner::STATUS_SKIPPED; | ||
|
||
$this->result->startTest($this); | ||
|
||
$this->result->addError( | ||
$this, | ||
new SkippedTestError( | ||
\sprintf( | ||
'This test depends on "%s" to pass.', | ||
$dependency | ||
) | ||
), | ||
0 | ||
); | ||
if ( | ||
!isset($skippedKeys[$dependency]) | ||
&& !isset($failedKeys[$dependency]) | ||
&& \strpos($dependency, '::') > 0 | ||
&& $className !== \explode('::', $dependency, 2)[0] | ||
) { | ||
$dependencyClass = \explode('::', $dependency, 2)[0]; | ||
(new TestSuite($dependencyClass, 'Dependency_' . \ucfirst($dependencyClass))) | ||
->run($this->result); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😨 This is scary bit of code. It fires off a lot of logic that will have unforeseen consequences, I'm just not sure which at the moment. If I am reading this correctly, this code does the following:
I get what you are trying to achieve: auto-run dependencies without any hassle on the user side. If this logic were to be accepted, it needs more safeguards and refactoring:
Tests, tests and more tests. Preferably a few end-to-end ones :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I know... Kinda the way to deal with it, when I cannot access the list of tests to execute. Another solution would be scanning all files which depends on which one and reorder them. However, I tried it without success.
Yup.
Good question. I will check what happens.
Not sure how to implement those at all...
More specific implementation how to do it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, this issue showing in the image has been fixed.. |
||
} else { | ||
$this->status = BaseTestRunner::STATUS_SKIPPED; | ||
|
||
$this->result->startTest($this); | ||
|
||
$this->result->addError( | ||
$this, | ||
new SkippedTestError( | ||
\sprintf( | ||
'This test depends on "%s" to pass.', | ||
$dependency | ||
) | ||
), | ||
0 | ||
); | ||
$this->result->endTest($this, 0); | ||
|
||
$this->result->endTest($this, 0); | ||
return false; | ||
} | ||
} | ||
|
||
return false; | ||
$dependencyName = false; | ||
if (isset($passed[$dependency])) | ||
{ | ||
$dependencyName = $dependency; | ||
} else if (isset($passed[$dependency.$this->getDataSetAsString(false)])) | ||
{ | ||
$dependencyName = $dependency.$this->getDataSetAsString(false); | ||
} | ||
|
||
if (isset($passed[$dependency])) { | ||
if ($passed[$dependency]['size'] != \PHPUnit\Util\Test::UNKNOWN && | ||
if ($dependencyName) { | ||
if ($passed[$dependencyName]['size'] != \PHPUnit\Util\Test::UNKNOWN && | ||
$this->getSize() != \PHPUnit\Util\Test::UNKNOWN && | ||
$passed[$dependency]['size'] > $this->getSize()) { | ||
$passed[$dependencyName]['size'] > $this->getSize()) { | ||
$this->result->addError( | ||
$this, | ||
new SkippedTestError( | ||
|
@@ -1764,11 +1815,11 @@ private function handleDependencies(): bool | |
$deepCopy = new DeepCopy; | ||
$deepCopy->skipUncloneable(false); | ||
|
||
$this->dependencyInput[$dependency] = $deepCopy->copy($passed[$dependency]['result']); | ||
$this->dependencyInput[$dependency] = $deepCopy->copy($passed[$dependencyName]['result']); | ||
} elseif ($shallowClone) { | ||
$this->dependencyInput[$dependency] = clone $passed[$dependency]['result']; | ||
$this->dependencyInput[$dependency] = clone $passed[$dependencyName]['result']; | ||
} else { | ||
$this->dependencyInput[$dependency] = $passed[$dependency]['result']; | ||
$this->dependencyInput[$dependency] = $passed[$dependencyName]['result']; | ||
} | ||
} else { | ||
$this->dependencyInput[$dependency] = null; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The substring
with [data set]
is dependent on how test names are send to the loggers. This could change in the future, for example with #3439You can retrieve the
TestCase
via$failure->failedTest()
and explore if it has a data set using$test->dataName()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this is the way how it is used elsewhere also.
At that point only thing what I'm interested about is
\some\namespace\class::someFunction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used like this elsewhere indeed! Which keeps giving me headaches as I am trying to refactor it out. 😆 For the test execution reordering and TestDox original-ordering, I cooked up this one:
phpunit/src/Runner/TestSuiteSorter.php
Lines 77 to 94 in b8f38d3
The
with data set
substring is a user interface element that should be independent of the inner workings of the test runner. Here's an upcoming change that might interfere with your code: 06d8c4bThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okey, I'm still not sure how you're gonna replace that "with data set". You would need also refactor these
phpunit/src/Framework/TestCase.php
Lines 1685 to 1780 in b8f38d3
phpunit/src/Framework/TestCase.php
Lines 1097 to 1116 in b8f38d3
I'm still not sure how these should be refactored.
Also I'm not sure how I can access dependencies of test inside of TestSuiteSorter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's enough to refactor for everyone! Don't be shy, just grab a few classes and have at it. 🛠
You can get the name of a
TestCase
with:$testCase->getName($withDataSet)
which gives you the name with(out) a prettified data set$testCase->dataName()
returns the name of the data set you see ingetName()
$testCase->getDependencies()
returns a list of dependencies, if anyPlease explore the surrounding code a bit more and write tests before you make such large changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand and I would like to fix things. However I want remind about few facts.
I'm using heavily my own time to fix & learn this stuff. It's not as simple as it looks for guy who have no experience with PHPUnit core. I will look into this after I have created some tests.
Would need this feature ASAP into PHPUnit...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get it, no worries! Like many other tools and frameworks PHPUnit is maintained by volunteer contributors. We are paid in emoji and sleepless nights.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@epdenouden Tests are now Implemented 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@epdenouden Btw, cannot really remove this
$pos = \strpos($failure->getTestName(), ' with data set');
Because if taking look into
src/Framework/TestFailure.php
there will beSame with other stuff. Meaning this needs to be refactored and refactoring this means refactoring also skipped, passed, etc... Would change little bit too much logic to be in this PR.