sebastianbergmann / phpunit

The PHP Unit Testing framework.
https://phpunit.de/
BSD 3-Clause "New" or "Revised" License
19.69k stars 2.2k forks source link

PhpStorm/Teamcity + PhpUnit 7.4.1 - Error in setUpBeforeClass #3364

Closed MaximilianKresse closed 5 years ago

MaximilianKresse commented 6 years ago
Q A
PHPUnit version >=7.4.0
PHP version 7.1.8
Installation Method Composer

Sample:

{
    "require": {
        "php": "^7.1"
    },

    "require-dev": {
        "phpunit/phpunit": "^7.4"
    }
}
<?php
declare(strict_types=1);

use PHPUnit\Framework\TestCase;

require_once __DIR__ . '/../vendor/autoload.php';

class JustATest extends TestCase
{
    public static function setUpBeforeClass(): void
    {
        throw new \RuntimeException('Something\'s not quite right!');
    }

    public function testSomething(): void
    {
        $this->fail('This cannot work!');
    }
}

When I run this test in phpstorm i will just get "Empty test suite." with the success icon without any failed test. Full output:

PHPUnit 7.4.3 by Sebastian Bergmann and contributors.

Empty test suite.

Time: 64 ms, Memory: 2.00MB

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

Process finished with exit code 2

There seems to be an critical error in the teamcity logger (src/Util/Log/TeamCity.php). You added some "if (!$test instanceof TestCase) {return;}" in the last version and this also seem to trigger this error (or rather don't trigger an error). When I change the addError method to the following everything works like expected:

public function addError(Test $test, \Throwable $t, float $time): void
    {
        if (!$test instanceof TestCase && !$test instanceof TestSuite) {
            return;
        }

I'm not sure whether this is everything to fully fix this bug. Propably the other added if-statements also have to be changed like this.

sebastianbergmann commented 6 years ago

ping @SvetlanaZem

SvetlanaZem commented 6 years ago

@sebastianbergmann Thank you! @wbars Would you please take a look?

wbars commented 6 years ago

@sebastianbergmann Why !$test instanceof TestCase check was introduced in the first place? As I can tell, here is flow of the problem:

After that we got unexpected inconsistent state when we run 0 tests, but no one register at least one skipped/error/assertion and after that unexpected behaviour about the icons come in.

If !$test instanceof TestCase is not crucial I suggest to simply remove them. Otherwise please tell and we will try to figure something out.

MaximilianKresse commented 6 years ago

Because of no further reaction I have created a pull request with a fix for this.

As far as I can see the !$test instanceof TestCase was introduced to clear some errors from Phan (without enough thinking what the change really does). If I inspected the code for ResultPrinters correctly there can be TestCases and TestSuites - both have a getName method but the interface noted in the method signature is only a Test which doesn't have a getName method.

One way to fix this could be the change the Test interface and add a getName() method but because of my lack of knowledge of the phpunit code base I choose to just "improve" !$test instanceof TestCase to !$test instanceof TestCase && !$test instanceof TestSuite where it makes sense.

epdenouden commented 6 years ago

Checking for instanceof TestCase is not enough, @dataprovider driven tests are instances of DataProviderTestSuite which would be covered by instanceof TestSuite.

This has caused quite a few bugs and oversights for the test execution ordering. Some background in #3396.

MaximilianKresse commented 5 years ago

@epdenouden Just to confirm that I'm reading your comment correctly: You're confirming that the actual code is bugged and it's not enough and that checking against instanceof TestCase AND instanceof TestSuite would fixing it, correct? Because there seems to be some kind of confusion...

epdenouden commented 5 years ago

@SvetlanaZem @wbars I have time to look into this in depth and have created a branch with some first tests to isolate the issues. It seems there is more than one thing going on. Different scenarios give very different result outputs.

Branch: https://github.com/epdenouden/phpunit/tree/issue-3364-teamcity-missing-error

Default and TestDox result printer do show setUpBeforeClass error

🔬 Default printer example:

./phpunit \
  tests/end-to-end/regression/GitHub/3364/Issue3364SetupBeforeClassTest.php

✂️
There were 2 errors:

1) Issue3364SetupBeforeClassTest
RuntimeException: throw exception in setUpBeforeClass in /Users/ewout/proj/phpunit-new-order/tests/end-to-end/regression/GitHub/3364/Issue3364SetupBeforeClassTest.php:18
Stack trace:
#0 /Users/ewout/proj/phpunit-new-order/src/Framework/TestSuite.php(703): Issue3364SetupBeforeClassTest::setUpBeforeClass()
#1 /Users/ewout/proj/phpunit-new-order/src/TextUI/TestRunner.php(622): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
✂️

🔬TestDox example:

./phpunit \
  --testdox \
  tests/end-to-end/regression/GitHub/3364/Issue3364SetupBeforeClassTest.php

✂️ 
Issue3364SetupBeforeClassTest
 ✘ Error bootstapping suite (most likely in Issue3364SetupBeforeClassTest::setUpBeforeClass) [0.00 ms]
   │
   │ RuntimeException: throw exception in setUpBeforeClass in /Users/ewout/proj/phpunit-new-order/tests/end-to-end/regression/GitHub/3364/Issue3364SetupBeforeClassTest.php:18
   │ Stack trace:
   │ #0 /Users/ewout/proj/phpunit-new-order/src/Framework/TestSuite.php(703): Issue3364SetupBeforeClassTest::setUpBeforeClass()
✂️ 

🔬TeamCity however doesn't show anything useful...

./phpunit \
  --teamcity \
  tests/end-to-end/regression/GitHub/3364/Issue3364SetupBeforeClassTest.php

✂️ 
##teamcity[testCount count='2' flowId='85156']

##teamcity[testSuiteStarted name='Issue3364SetupBeforeClassTest' locationHint='php_qn:///Users/ewout/proj/phpunit-new-order/tests/end-to-end/regression/GitHub/3364/Issue3364SetupBeforeClassTest.php::\Issue3364SetupBeforeClassTest' flowId='85156']

##teamcity[testSuiteFinished name='Issue3364SetupBeforeClassTest' flowId='85156']
✂️ 
wbars commented 5 years ago

@sebastianbergmann @epdenouden Please refer my previous comment again about the source of the bug.

Since still nobody shared the details behind introduced check and commit message does't do it either it's unclear for me why it should be kept and I still suggest simply remove the check or at least patch it with && !$test instanceof TestSuite as OP suggests (so from this point of view this PR looks OK to me.

\PHPUnit\Framework\TestResult::addError is invoked only with TestCase and TestSuite as first argument so I don't see how this check can help TeamCity (e.g. PhpStorm) logger. If it's crucial for PHPUnit ecosystem, please share insights.

epdenouden commented 5 years ago

@wbars Apologies I didn't make it clear in my reply, your investigation helped pinpointing the problem. I am not sure why the extra check for just TestCase ended up there. I will check the history and see if it related to other bugs. Seems to be just a case of codestyle fixes? The commit message just says "Fix issues identified by Phan".

In any case there needs to be an error emitted somehow about the failing fixtures. I'll look into this.

epdenouden commented 5 years ago

I think I have found a nice fix.

image

epdenouden commented 5 years ago

@MaximilianKresse and @wbars thanks to both of you for your patience providing ongoing feedback and insight. Maximilian, eventhough your PR didn't get merged, it did provide a quick starting point for further investigation and helped me find the root cause. Thank you.

I have proposed a fix for the underlying problem in #3428. Summary: when setup failed, the TestSuite would report itself to the listener for each and every underlying test. Patching up the TeamCity printer would have hidden the problem again.

The TeamCity and other listeners and printers are going to get a nice rewrite for PHPUnit 8. Let me know if you have any other concerns. (preferably in a seperate ticket :)

epdenouden commented 5 years ago

@SvetlanaZem @wbars I am working on a POC for an update to the event+logger system of PHPUnit and want to use the TeamCity format as one of the main test cases, as it is async, notices changes in TestSuite and supports parallel testing.

Can you help me get in touch with the proper contact at JetBrains?

wbars commented 5 years ago

@epdenouden Please feel free to write an email for me: kirill.smelov at jetbrains dot com.