Mocking DateTimeInterface objects distorts space and time
dinamic opened this issue · 10 comments
Q | A |
---|---|
phpunit-mock-objects version | x.y.z |
PHPUnit version | 7.2.6 |
PHP version | 7.2.7 |
Installation Method | Composer |
Tested with | xdebug 2.6.0, phpdbg 7.2.7 |
While working on trying to get some adequate unit tests I stumbled upon a case where I had to mock DateTimeInterface objects. Seems like there's something weird going on with those. Consider the example below. Both should fail, alas one succeeds.
What's going on? Is this expected behaviour? Sounds like DateTimeInterface objects are messed up so bad they distort the universe around them.
P.S This may not be the correct repository. Maybe I should move this one to phpunit? I don't seem to have phpunit-mock-objects installed.
# composer show | grep -i phpunit
phpunit/php-code-coverage 6.0.7 Library that provides collection, processing, and rendering functionality for PHP code coverage information.
phpunit/php-file-iterator 2.0.1 FilterIterator implementation that filters files based on a list of suffixes.
phpunit/php-text-template 1.2.1 Simple template engine.
phpunit/php-timer 2.0.0 Utility class for timing
phpunit/php-token-stream 3.0.0 Wrapper around PHP's tokenizer extension.
phpunit/phpunit 7.2.6 The PHP Unit Testing framework.
symfony/phpunit-bridge v4.1.1 Symfony PHPUnit Bridge
<?php
class DateTimeInterfaceMockingTest extends \PHPUnit\Framework\TestCase
{
public function testExecuteWillNotFailBecauseTrueEqualsFalse(): void
{
$mockDateTime = $this->createMock(DateTimeInterface::class);
$this->assertFalse(true);
$this->assertTrue(false);
}
public function testExecuteWillFailBecauseTrueEqualsFalseAndMockingPositionDoesMatter(): void
{
$this->assertFalse(true);
$this->assertTrue(false);
$mockDateTime = $this->createMock(DateTimeInterface::class);
}
public function testExecuteWillFailBecauseTrueDoesNotEqualsFalse(): void
{
$this->assertFalse(true);
$this->assertTrue(false);
}
}
# vendor/bin/phpunit ./test.php --no-coverage
PHPUnit 7.2.6 by Sebastian Bergmann and contributors.
Testing DateTimeInterfaceMockingTest
.FF 3 / 3 (100%)
Time: 462 ms, Memory: 14.00MB
There were 2 failures:
1) DateTimeInterfaceMockingTest::testExecuteWillFailBecauseTrueEqualsFalseAndMockingPositionDoesMatter
Failed asserting that true is false.
/Users/nikola/Projects/Jiminny/app/test.php:15
2) DateTimeInterfaceMockingTest::testExecuteWillFailBecauseTrueDoesNotEqualsFalse
Failed asserting that true is false.
/Users/nikola/Projects/Jiminny/app/test.php:23
FAILURES!
Tests: 3, Assertions: 2, Failures: 2.
If this only happens with PHPUnit 7.2 then, yes, this should be reported in the main PHPUnit repository. If this also happens with PHPUnit 6.5 then this is the right repository.
Just to iterate on this. Seems like mocking DateTime
and DateTimeImmutable
works fine. Mocking towards DateTimeinterface
seems to be the problem here.
While this might be a bug (I have not investigated it yet), I personally would not stub/mock DateTimeImmutable
(or DateTime
) as I do not stub/mock value objects.
Maybe @derickr can provide insight why DateTimeInterface
might be special.
It may be worth mentioning that it fails using both xdebug and phpdbg, so is not specific to either.
How would this be related to code coverage data collection? I pinged @derickr on this because he maintains ext/date
, not because he maintains Xdebug :-)
Tried ignoring the current configuration that I've got and something interesting happened.
PHP Fatal error: DateTimeInterface can't be implemented by user classes in /Users/nikola/Projects/RandomProject/app/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php(603) : eval()'d code on line 1
Full log here: https://pastebin.com/iHitmD23
Here's my phpunit.xml.dist:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="bootstrap/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false">
<testsuites>
<testsuite name="Application Test Suite">
<directory suffix="Test.php">./tests/unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<ini name="error_reporting" value="E_STRICT | E_ALL" />
</php>
<logging>
<log type="coverage-clover" target="build/coverage.xml"/>
</logging>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
</phpunit>
Seems like the error_reporting
is silencing the error.
Using 32767
instead of the value E_STRICT | E_ALL
makes the fatal error apparent.
I guess I should close this one as it seems like a misconfiguration on my part more than anything else.
@sebastianbergmann, is support for php constants in the ini section of the config file on the roadmap of features to expect?
When I was faced with the issue I was trying to figure out how to mock DateTimeInterface
objects while comparing them. Do you happen to know what method do the comparison operators invoke? Or would they call one, actually. It very well could be some php internals logic.
Just use "-1" everywhere, for error_reporting
:-)