-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Deprecate Prophecy integration #4141
Comments
Sketch of what unbundling would entail: diff --git a/build.xml b/build.xml
index 054b1d1e2..88bba98a0 100644
--- a/build.xml
+++ b/build.xml
@@ -284,54 +284,12 @@
</fileset>
</copy>
- <copy file="${basedir}/vendor/phpdocumentor/reflection-common/LICENSE" tofile="${basedir}/build/tmp/phar/phpdocumentor-reflection-common/LICENSE"/>
- <copy todir="${basedir}/build/tmp/phar/phpdocumentor-reflection-common">
- <fileset dir="${basedir}/vendor/phpdocumentor/reflection-common/src">
- <include name="**/*.php" />
- </fileset>
- </copy>
-
- <copy file="${basedir}/vendor/phpdocumentor/reflection-docblock/LICENSE" tofile="${basedir}/build/tmp/phar/phpdocumentor-reflection-docblock/LICENSE"/>
- <copy todir="${basedir}/build/tmp/phar/phpdocumentor-reflection-docblock">
- <fileset dir="${basedir}/vendor/phpdocumentor/reflection-docblock/src">
- <include name="**/*.php" />
- </fileset>
- </copy>
-
- <copy file="${basedir}/vendor/phpdocumentor/type-resolver/LICENSE" tofile="${basedir}/build/tmp/phar/phpdocumentor-type-resolver/LICENSE"/>
- <copy todir="${basedir}/build/tmp/phar/phpdocumentor-type-resolver">
- <fileset dir="${basedir}/vendor/phpdocumentor/type-resolver/src">
- <include name="**/*.php" />
- </fileset>
- </copy>
-
- <copy file="${basedir}/vendor/phpspec/prophecy/LICENSE" tofile="${basedir}/build/tmp/phar/phpspec-prophecy/LICENSE"/>
- <copy todir="${basedir}/build/tmp/phar/phpspec-prophecy">
- <fileset dir="${basedir}/vendor/phpspec/prophecy/src">
- <include name="**/*.php" />
- </fileset>
- </copy>
-
- <copy file="${basedir}/vendor/symfony/polyfill-ctype/LICENSE" tofile="${basedir}/build/tmp/phar/symfony-polyfill-ctype/LICENSE"/>
- <copy todir="${basedir}/build/tmp/phar/symfony-polyfill-ctype">
- <fileset dir="${basedir}/vendor/symfony/polyfill-ctype">
- <include name="**/*.php" />
- </fileset>
- </copy>
-
<copy file="${basedir}/vendor/theseer/tokenizer/LICENSE" tofile="${basedir}/build/tmp/phar/theseer-tokenizer/LICENSE"/>
<copy todir="${basedir}/build/tmp/phar/theseer-tokenizer">
<fileset dir="${basedir}/vendor/theseer/tokenizer/src">
<include name="**/*.php" />
</fileset>
</copy>
-
- <copy file="${basedir}/vendor/webmozart/assert/LICENSE" tofile="${basedir}/build/tmp/phar/webmozart-assert/LICENSE"/>
- <copy todir="${basedir}/build/tmp/phar/webmozart-assert">
- <fileset dir="${basedir}/vendor/webmozart/assert/src">
- <include name="**/*.php" />
- </fileset>
- </copy>
</target>
<target name="-phar-build" depends="-phar-determine-version">
diff --git a/composer.json b/composer.json
index de6951944..64bc98069 100644
--- a/composer.json
+++ b/composer.json
@@ -33,7 +33,6 @@
"myclabs/deep-copy": "^1.9.1",
"phar-io/manifest": "^1.0.3",
"phar-io/version": "^2.0.1",
- "phpspec/prophecy": "^1.8.1",
"phpunit/php-code-coverage": "^8.0.1",
"phpunit/php-file-iterator": "^3.0",
"phpunit/php-invoker": "^3.0",
diff --git a/src/Framework/TestCase.php b/src/Framework/TestCase.php
index 9a91415d2..db69c7131 100644
--- a/src/Framework/TestCase.php
+++ b/src/Framework/TestCase.php
@@ -42,10 +42,6 @@
use PHPUnit\Util\PHP\AbstractPhpProcess;
use PHPUnit\Util\Test as TestUtil;
use PHPUnit\Util\Type;
-use Prophecy\Exception\Prediction\PredictionException;
-use Prophecy\Prophecy\MethodProphecy;
-use Prophecy\Prophecy\ObjectProphecy;
-use Prophecy\Prophet;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
use SebastianBergmann\Diff\Differ;
@@ -230,11 +226,6 @@ abstract class TestCase extends Assert implements SelfDescribing, Test
*/
private $snapshot;
- /**
- * @var \Prophecy\Prophet
- */
- private $prophet;
-
/**
* @var bool
*/
@@ -1051,9 +1042,6 @@ public function runBare(): void
} catch (AssertionFailedError $e) {
$this->status = BaseTestRunner::STATUS_FAILURE;
$this->statusMessage = $e->getMessage();
- } catch (PredictionException $e) {
- $this->status = BaseTestRunner::STATUS_FAILURE;
- $this->statusMessage = $e->getMessage();
} catch (\Throwable $_e) {
$e = $_e;
$this->status = BaseTestRunner::STATUS_ERROR;
@@ -1061,7 +1049,6 @@ public function runBare(): void
}
$this->mockObjects = [];
- $this->prophet = null;
// Tear down the fixture. An exception raised in tearDown() will be
// caught and passed on when no exception was raised before.
@@ -1119,10 +1106,6 @@ public function runBare(): void
// Workaround for missing "finally".
if (isset($e)) {
- if ($e instanceof PredictionException) {
- $e = new AssertionFailedError($e->getMessage());
- }
-
$this->onNotSuccessfulTest($e);
}
}
@@ -1838,24 +1821,6 @@ protected function getObjectForTrait($traitName, array $arguments = [], $traitCl
);
}
- /**
- * @param null|string $classOrInterface
- *
- * @throws \Prophecy\Exception\Doubler\ClassNotFoundException
- * @throws \Prophecy\Exception\Doubler\DoubleException
- * @throws \Prophecy\Exception\Doubler\InterfaceNotFoundException
- *
- * @psalm-param class-string|null $classOrInterface
- */
- protected function prophesize($classOrInterface = null): ObjectProphecy
- {
- if (\is_string($classOrInterface)) {
- $this->recordDoubledType($classOrInterface);
- }
-
- return $this->getProphet()->prophesize($classOrInterface);
- }
-
/**
* Creates a default TestResult object.
*
@@ -1929,22 +1894,6 @@ private function verifyMockObjects(): void
$this->shouldInvocationMockerBeReset($mockObject)
);
}
-
- if ($this->prophet !== null) {
- try {
- $this->prophet->checkPredictions();
- } finally {
- foreach ($this->prophet->getProphecies() as $objectProphecy) {
- foreach ($objectProphecy->getMethodProphecies() as $methodProphecies) {
- foreach ($methodProphecies as $methodProphecy) {
- \assert($methodProphecy instanceof MethodProphecy);
-
- $this->numAssertions += \count($methodProphecy->getCheckedPredictions());
- }
- }
- }
- }
- }
}
private function handleDependencies(): bool
@@ -2206,9 +2155,7 @@ private function createGlobalStateSnapshot(bool $backupGlobals): Snapshot
$blacklist->addClassNamePrefix('SebastianBergmann\Template');
$blacklist->addClassNamePrefix('SebastianBergmann\Timer');
$blacklist->addClassNamePrefix('PHP_Token');
- $blacklist->addClassNamePrefix('Symfony');
$blacklist->addClassNamePrefix('Doctrine\Instantiator');
- $blacklist->addClassNamePrefix('Prophecy');
foreach ($this->backupStaticAttributesBlacklist as $class => $attributes) {
foreach ($attributes as $attribute) {
@@ -2282,15 +2229,6 @@ private function compareGlobalStateSnapshotPart(array $before, array $after, str
}
}
- private function getProphet(): Prophet
- {
- if ($this->prophet === null) {
- $this->prophet = new Prophet;
- }
-
- return $this->prophet;
- }
-
/**
* @throws \SebastianBergmann\ObjectEnumerator\InvalidArgumentException
*/
diff --git a/src/Util/Blacklist.php b/src/Util/Blacklist.php
index ed726077d..f41860f51 100644
--- a/src/Util/Blacklist.php
+++ b/src/Util/Blacklist.php
@@ -15,11 +15,7 @@
use PharIo\Manifest\Manifest;
use PharIo\Version\Version as PharIoVersion;
use PHP_Token;
-use phpDocumentor\Reflection\DocBlock;
-use phpDocumentor\Reflection\Project;
-use phpDocumentor\Reflection\Type;
use PHPUnit\Framework\TestCase;
-use Prophecy\Prophet;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeUnitReverseLookup\Wizard;
use SebastianBergmann\Comparator\Comparator;
@@ -37,7 +33,6 @@
use SebastianBergmann\Type\TypeName;
use SebastianBergmann\Version;
use TheSeer\Tokenizer\Tokenizer;
-use Webmozart\Assert\Assert;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -72,9 +67,6 @@ final class Blacklist
// phpdocumentor/type-resolver
Type::class => 1,
- // phpspec/prophecy
- Prophet::class => 1,
-
// phpunit/phpunit
TestCase::class => 2, |
@sebastianbergmann just a few questions :)
Note on the last point for anyone else reading this, the current way would be to change: <?php
class UserTest extends PHPUnit\Framework\TestCase
{
public function testPasswordHashing()
{
$hasher = $this->prophesize('App\Security\Hasher');
$user = new App\Entity\User($hasher->reveal());
$hasher->generateHash($user, 'qwerty')->willReturn('hashed_pass');
$user->setPassword('qwerty');
$this->assertEquals('hashed_pass', $user->getPassword());
}
} to this: <?php
class UserTest extends PHPUnit\Framework\TestCase
{
private $prophet;
public function testPasswordHashing()
{
$hasher = $this->prophet->prophesize('App\Security\Hasher');
$user = new App\Entity\User($hasher->reveal());
$hasher->generateHash($user, 'qwerty')->willReturn('hashed_pass');
$user->setPassword('qwerty');
$this->assertEquals('hashed_pass', $user->getPassword());
}
protected function setUp()
{
$this->prophet = new \Prophecy\Prophet;
}
protected function tearDown()
{
$this->prophet->checkPredictions();
}
} This is not that huge of a deal mind you, but I personally find this a bit error-prone: it's easy to forget Maybe the following could be added? namespace PHPUnit\Framework;
abstract class ProphecyTestCase TestCase
{
private $prophet;
protected function setUp()
{
$this->prophet = new \Prophecy\Prophet;
}
protected function tearDown()
{
$this->prophet->checkPredictions();
}
final protected function prophesize($classOrInterface = null): ObjectProphecy
{
if ($this->prophet === null) {
$this->prophet = new Prophet;
}
return $this->prophet;
}
} |
Hm actually if there is a |
Makes sense to me to unbundle; if people like it they only need to add the one dependency. I would worry that currently there aren't good, easy to find Prophecy docs so it'd be good to retain those pages in the phpunit docs until that happens |
@ciaranmcnulty It's not just "adding the dependency", though. Without an integration such as the one provided right now, PHPUnit will mark a test as risky if it only has expectations performed through Prophecy. @theofidry A |
Could we still use this if we install it manually? I'm using it a lot 😬 |
Then, making sure it is possible should be a prerequisite of this unbundling. After that, we could resurrect https://github.com/phpspec/prophecy-phpunit |
sad news. I love phpunit+prophecy :( |
I'm wondering if it will be possible to provide a way to use phpunit as a phar with the extension of prophecy. I do prefer the phar installs because it reduces the risks of conflicting dependencies like you are experiencing with prophecy and phpunit. If it is possible the migration path seems feasible |
I am assuming there has already been communication between you and @ciaranmcnulty about whether this circular dependency can be solved? If that is the only bump in the road, it would make sense to try and fix that. I'd hate to see Prophecy integration go. Better yet, I'd love a tighter integration (if at all possible). I use Prophecy on all projects and If you will indeed deprecate the integration, would there be a chance of adding hooks to PHPUnit to ensure Prophecy or a glue package to hook into PHPUnit to at least prevent the risky test warning? |
I have made changes to <?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
use Prophecy\Exception\Doubler\DoubleException;
use Prophecy\Exception\Doubler\InterfaceNotFoundException;
use Prophecy\Exception\Prediction\PredictionException;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophet;
abstract class ProphecyTestCase extends TestCase
{
/**
* @var Prophet
*/
private $prophet;
/**
* @throws DoubleException
* @throws InterfaceNotFoundException
*
* @psalm-param class-string|null $type
*/
protected function prophesize(?string $classOrInterface = null): ObjectProphecy
{
if (\is_string($classOrInterface)) {
$this->recordDoubledType($classOrInterface);
}
return $this->getProphet()->prophesize($classOrInterface);
}
protected function verifyMockObjects(): void
{
parent::verifyMockObjects();
if ($this->prophet !== null) {
try {
$this->prophet->checkPredictions();
} catch (PredictionException $e) {
throw new AssertionFailedError($e->getMessage());
} finally {
foreach ($this->prophet->getProphecies() as $objectProphecy) {
foreach ($objectProphecy->getMethodProphecies() as $methodProphecies) {
foreach ($methodProphecies as $methodProphecy) {
\assert($methodProphecy instanceof MethodProphecy);
$this->addToAssertionCount(\count($methodProphecy->getCheckedPredictions()));
}
}
}
}
}
}
private function getProphet(): Prophet
{
if ($this->prophet === null) {
$this->prophet = new Prophet;
}
return $this->prophet;
}
} |
@stof @ciaranmcnulty Where should |
This discussion / these changes might also be of interest to @davedevelopment, @robertbasic, @padraic et. al. for |
@stof Yes, I think that would be best. |
@stof @ciaranmcnulty I have forked your There are currently two open issues:
I will work on https://github.com/sebastianbergmann/prophecy-phpunit/issues/2 ASAP but probably need help with https://github.com/sebastianbergmann/prophecy-phpunit/issues/1. Can you please unarchive |
@TomasVotruba Eventually a rector would be nice that looks for classes that extend |
@sebastianbergmann Sure, that can be done. |
IMHO a trait would be simpler |
A trait cannot override |
My issue is that in Symfony, the usually extends KernelTestCase (and this one extends Phpunit\Framework\TestCase). So if it's not a trait, a test will not be able to use prophecy anymore |
I'm pretty sure it would be possible to work with the Symfony team on getting support for the new |
The pull request for |
Sure;
As do I :-) |
Sorry to jump in here:
Is there a "package distribution" for phpunits phar similar to e.g. phpstan? I would love to use the phar, but not having it in Is there something like this (or did I just miss it)? thanks! |
@mfn I think you should create a separate issue to discuss that, as it is not about deprecating prophecy anymore. |
Installing PHPUnit or other tools as phar is not a problem: Dealing with extensions is currently a problem as that opens up dependency resolving. Something that phive's infrastructure currently does not have the meta data for. That means for extensions we have to come up with a means to enable phive to resolve what version of an extension is compatible with what version of, for instance, PHPUnit - prefereably without downloading all versions first ;) I do have some work in progress code for that but it's more like an experiment at the moment and as much as I hate it, open source work does not have priority at the moment... |
Did someone already build an extension-phar that can be loaded as Sebastian stated? @stof maybe this can be added to phpspec/prophecy-phpunit? |
Ok, got it working. Was thinking in the wrong direction first, got errors because I already added prophecy to the phar - but this should only be the case for a phpunit-10 compatible version, since phpunit-9 already has prophecy included... but works nicely, I used the build-mechanism from Sebastians phpunit-example-extension. |
Just in case it was lost in PR references, the @rectorphp migration is ready: tl;dr; composer require rector/rector --dev
vendor/bin/rector process /tests --set phpunit91 |
In PHPUnit 9, Prophecy integration was deprecated, see sebastianbergmann/phpunit#4141. phpspec/prophecy-phpunit was added to support prophecy calls.
5 years ago, with version 4.5, PHPUnit started to bundle phpspec/prophecy as an alternative to PHPUnit's own test double functionality.
In the context of the above, "bundling" means that
phpspec/prophecy
is listed as a dependency in PHPUnit'scomposer.json
filephpunit.phar
, the PHAR distribution of PHPUnit, contains Prophecy as well as its dependenciesPHPUnit\Framework\TestCase
provides theprophesize()
method to create a test double using Prophecy (allowingTestCase
to automatically verify Prophecy expectations at the end of the test while also providing integration with PHPUnit's risky test analysis)5 years ago, I wrote in an article
This has not happended so far and I now doubt that it will.
phpspec/prophecy
depends on thesebastian/comparator
andsebastian/recursion-context
components that are used by PHPUnit. And since PHPUnit currently depends onphpspec/prophecy
we have circular dependencies.These circular dependencies are especially annoying whenever I bump the major version of
sebastian/comparator
andsebastian/recursion-context
because @ciaranmcnulty needs to make the same change inphpspec/prophecy
at the same time (otherwise PHPUnit breaks).It is because of this circular dependency that I am beginning to think that the tight integration of Prophecy into PHPUnit causes more harm than good.
I would like to deprecate
PHPUnit\Framework\TestCase::prophesize()
(and any associated functionality) in PHPUnit 9.X and remove it in PHPUnit 10.The text was updated successfully, but these errors were encountered: